Initial Contribution
diff --git a/libcore/security/MODULE_LICENSE_APACHE2 b/libcore/security/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e0940a1
--- /dev/null
+++ b/libcore/security/MODULE_LICENSE_APACHE2
@@ -0,0 +1 @@
+For Harmony code
diff --git a/libcore/security/MODULE_LICENSE_BSD_LIKE b/libcore/security/MODULE_LICENSE_BSD_LIKE
new file mode 100644
index 0000000..3ffcd33
--- /dev/null
+++ b/libcore/security/MODULE_LICENSE_BSD_LIKE
@@ -0,0 +1 @@
+For Bouncy Castle
diff --git a/libcore/security/bouncycastle-license.txt b/libcore/security/bouncycastle-license.txt
new file mode 100644
index 0000000..cfeef72
--- /dev/null
+++ b/libcore/security/bouncycastle-license.txt
@@ -0,0 +1,21 @@
+Copyright (c) 2000 - 2006 The Legion Of The Bouncy Castle
+(http://www.bouncycastle.org)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/libcore/security/src/main/files/cacerts.bks b/libcore/security/src/main/files/cacerts.bks
new file mode 100644
index 0000000..ee37790
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts.bks
Binary files differ
diff --git a/libcore/security/src/main/files/cacerts/03e16f6c.0 b/libcore/security/src/main/files/cacerts/03e16f6c.0
new file mode 100644
index 0000000..748dfa9
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/03e16f6c.0
@@ -0,0 +1,28 @@
+
+subject=/OU=Copyright (c) 1997 Microsoft Corp./OU=Microsoft Corporation/CN=Microsoft Root Authority
+issuer=/OU=Copyright (c) 1997 Microsoft Corp./OU=Microsoft Corporation/CN=Microsoft Root Authority
+-----BEGIN CERTIFICATE-----
+MIIEEjCCAvqgAwIBAgIPAMEAizw8iBHRPvZj7N9AMA0GCSqGSIb3DQEBBAUAMHAx
+KzApBgNVBAsTIkNvcHlyaWdodCAoYykgMTk5NyBNaWNyb3NvZnQgQ29ycC4xHjAc
+BgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEhMB8GA1UEAxMYTWljcm9zb2Z0
+IFJvb3QgQXV0aG9yaXR5MB4XDTk3MDExMDA3MDAwMFoXDTIwMTIzMTA3MDAwMFow
+cDErMCkGA1UECxMiQ29weXJpZ2h0IChjKSAxOTk3IE1pY3Jvc29mdCBDb3JwLjEe
+MBwGA1UECxMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSEwHwYDVQQDExhNaWNyb3Nv
+ZnQgUm9vdCBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQCpAr3BcOY78k4bKJ+XeF4w6qKpjSVf+P6VTKO3/p2iID58UaKboo9gMmvRQmR5
+7qx2yVTa8uuchhyPn4Rms8VremIj1h083g8BkuiWxL8tZpqaaCaZ0Dosvwy1WCbB
+RucKPjiWLKkoOajsSYNC44QPu5psVWGsgnyhYC13TOmZtGQ7mlAcMQgkFJ+p55Er
+GOY9mGMUYFgFZZ8dN1KH96fvlALGG9O/VUWziYC/OuxUlE6u/ad6bXROrxjMlgko
+IQBXkGBpN7tLEgc8Vv9b+6RmCgim0oFWV++2O14WgXcE2va+roCV/rDNf9anGnJc
+PMq88AijIjCzBoXJsyB3E4XfAgMBAAGjgagwgaUwgaIGA1UdAQSBmjCBl4AQW9Bw
+72lyniNRfhSyTY7/y6FyMHAxKzApBgNVBAsTIkNvcHlyaWdodCAoYykgMTk5NyBN
+aWNyb3NvZnQgQ29ycC4xHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEh
+MB8GA1UEAxMYTWljcm9zb2Z0IFJvb3QgQXV0aG9yaXR5gg8AwQCLPDyIEdE+9mPs
+30AwDQYJKoZIhvcNAQEEBQADggEBAJXoC8CN85cYNe24ASTYdxHzXGAyn54Lyz4F
+kYiPyTrmIfLwV5MstaBHyGLv/NfMOztaqTZUaf4kbT/JzKreBXzdMY09nxBwarv+
+Ek8YacD80EPjEVogT+pie6+qGcgrNyUtvmWhEoolD2Oj91Qc+SHJ1hXzUqxuQzIH
+/YIX+OVnbA1R9r3xUse958Qw/CAxCYgdlSkaTdUdAqXxgOADtFv0sd3IV+5lScdS
+VLa0AygS/5DW8AiPfriXxas3LOR65Kh343agANBqP8HSNorgQRKoNWobats14dQc
+BOSoRQTIWjM4bk0cDWK3CqKM09VUP0bNHFWmcNsSOoeTdZ+n0qA=
+-----END CERTIFICATE-----
+
diff --git a/libcore/security/src/main/files/cacerts/111e6273.0 b/libcore/security/src/main/files/cacerts/111e6273.0
new file mode 100644
index 0000000..908d85c
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/111e6273.0
@@ -0,0 +1,86 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            04:00:00:00:00:01:0f:86:26:e6:0d
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: OU=GlobalSign Root CA - R2, O=GlobalSign, CN=GlobalSign
+        Validity
+            Not Before: Dec 15 08:00:00 2006 GMT
+            Not After : Dec 15 08:00:00 2021 GMT
+        Subject: OU=GlobalSign Root CA - R2, O=GlobalSign, CN=GlobalSign
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:a6:cf:24:0e:be:2e:6f:28:99:45:42:c4:ab:3e:
+                    21:54:9b:0b:d3:7f:84:70:fa:12:b3:cb:bf:87:5f:
+                    c6:7f:86:d3:b2:30:5c:d6:fd:ad:f1:7b:dc:e5:f8:
+                    60:96:09:92:10:f5:d0:53:de:fb:7b:7e:73:88:ac:
+                    52:88:7b:4a:a6:ca:49:a6:5e:a8:a7:8c:5a:11:bc:
+                    7a:82:eb:be:8c:e9:b3:ac:96:25:07:97:4a:99:2a:
+                    07:2f:b4:1e:77:bf:8a:0f:b5:02:7c:1b:96:b8:c5:
+                    b9:3a:2c:bc:d6:12:b9:eb:59:7d:e2:d0:06:86:5f:
+                    5e:49:6a:b5:39:5e:88:34:ec:bc:78:0c:08:98:84:
+                    6c:a8:cd:4b:b4:a0:7d:0c:79:4d:f0:b8:2d:cb:21:
+                    ca:d5:6c:5b:7d:e1:a0:29:84:a1:f9:d3:94:49:cb:
+                    24:62:91:20:bc:dd:0b:d5:d9:cc:f9:ea:27:0a:2b:
+                    73:91:c6:9d:1b:ac:c8:cb:e8:e0:a0:f4:2f:90:8b:
+                    4d:fb:b0:36:1b:f6:19:7a:85:e0:6d:f2:61:13:88:
+                    5c:9f:e0:93:0a:51:97:8a:5a:ce:af:ab:d5:f7:aa:
+                    09:aa:60:bd:dc:d9:5f:df:72:a9:60:13:5e:00:01:
+                    c9:4a:fa:3f:a4:ea:07:03:21:02:8e:82:ca:03:c2:
+                    9b:8f
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            X509v3 Subject Key Identifier: 
+                9B:E2:07:57:67:1C:1E:C0:6A:06:DE:59:B4:9A:2D:DF:DC:19:86:2E
+            X509v3 CRL Distribution Points: 
+                URI:http://crl.globalsign.net/root-r2.crl
+
+            X509v3 Authority Key Identifier: 
+                keyid:9B:E2:07:57:67:1C:1E:C0:6A:06:DE:59:B4:9A:2D:DF:DC:19:86:2E
+
+    Signature Algorithm: sha1WithRSAEncryption
+        99:81:53:87:1c:68:97:86:91:ec:e0:4a:b8:44:0b:ab:81:ac:
+        27:4f:d6:c1:b8:1c:43:78:b3:0c:9a:fc:ea:2c:3c:6e:61:1b:
+        4d:4b:29:f5:9f:05:1d:26:c1:b8:e9:83:00:62:45:b6:a9:08:
+        93:b9:a9:33:4b:18:9a:c2:f8:87:88:4e:db:dd:71:34:1a:c1:
+        54:da:46:3f:e0:d3:2a:ab:6d:54:22:f5:3a:62:cd:20:6f:ba:
+        29:89:d7:dd:91:ee:d3:5c:a2:3e:a1:5b:41:f5:df:e5:64:43:
+        2d:e9:d5:39:ab:d2:a2:df:b7:8b:d0:c0:80:19:1c:45:c0:2d:
+        8c:e8:f8:2d:a4:74:56:49:c5:05:b5:4f:15:de:6e:44:78:39:
+        87:a8:7e:bb:f3:79:18:91:bb:f4:6f:9d:c1:f0:8c:35:8c:5d:
+        01:fb:c3:6d:b9:ef:44:6d:79:46:31:7e:0a:fe:a9:82:c1:ff:
+        ef:ab:6e:20:c4:50:c9:5f:9d:4d:9b:17:8c:0c:e5:01:c9:a0:
+        41:6a:73:53:fa:a5:50:b4:6e:25:0f:fb:4c:18:f4:fd:52:d9:
+        8e:69:b1:e8:11:0f:de:88:d8:fb:1d:49:f7:aa:de:95:cf:20:
+        78:c2:60:12:db:25:40:8c:6a:fc:7e:42:38:40:64:12:f7:9e:
+        81:e1:93:2e
+SHA1 Fingerprint=75:E0:AB:B6:13:85:12:27:1C:04:F8:5F:DD:DE:38:E4:B7:24:2E:FE
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
+A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
+Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
+MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
+A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
+v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
+eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
+tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
+C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
+zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
+mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
+V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
+bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
+3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
+J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
+291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
+ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
+AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
+TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/1155c94b.0 b/libcore/security/src/main/files/cacerts/1155c94b.0
new file mode 100644
index 0000000..3fc6648
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/1155c94b.0
@@ -0,0 +1,87 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=ES, L=C/ Muntaner 244 Barcelona, CN=Autoridad de Certificacion Firmaprofesional CIF A62634068/emailAddress=ca@firmaprofesional.com
+        Validity
+            Not Before: Oct 24 22:00:00 2001 GMT
+            Not After : Oct 24 22:00:00 2013 GMT
+        Subject: C=ES, L=C/ Muntaner 244 Barcelona, CN=Autoridad de Certificacion Firmaprofesional CIF A62634068/emailAddress=ca@firmaprofesional.com
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:e7:23:03:6f:6f:23:a5:5e:78:ce:95:2c:ed:94:
+                    1e:6e:0a:9e:01:c7:ea:30:d1:2c:9d:dd:37:e8:9b:
+                    98:79:56:d3:fc:73:df:d0:8a:de:55:8f:51:f9:5a:
+                    ea:de:b5:70:c4:ed:a4:ed:ff:a3:0d:6e:0f:64:50:
+                    31:af:01:27:58:ae:fe:6c:a7:4a:2f:17:2d:d3:73:
+                    d5:13:1c:8f:59:a5:34:2c:1d:54:04:45:cd:68:b8:
+                    a0:c0:03:a5:cf:85:42:47:95:28:5b:cf:ef:80:6c:
+                    e0:90:97:8a:01:3c:1d:f3:87:10:30:26:48:7d:d7:
+                    fc:e9:9d:91:71:ff:41:9a:a9:40:b5:37:9c:29:20:
+                    4f:1f:52:e3:a0:7d:13:6d:54:b7:0a:de:e9:6a:4e:
+                    07:ac:ac:19:5f:dc:7e:62:74:f6:b2:05:00:ba:85:
+                    a0:fd:1d:38:6e:cb:5a:bb:86:bc:94:67:33:35:83:
+                    2c:1f:23:cd:f8:c8:91:71:cc:97:8b:ef:ae:0f:dc:
+                    29:03:1b:c0:39:eb:70:ed:c1:6e:0e:d8:67:0b:89:
+                    a9:bc:35:e4:ef:b6:34:b4:a5:b6:c4:2d:a5:be:d0:
+                    c3:94:24:48:db:df:96:d3:00:b5:66:1a:8b:66:05:
+                    0f:dd:3f:3f:cb:3f:aa:5e:9a:4a:f8:b4:4a:ef:95:
+                    37:1b
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Alternative Name: 
+                URI:http://www.firmaprofesional.com
+            X509v3 Basic Constraints: critical
+                CA:TRUE, pathlen:1
+            X509v3 Private Key Usage Period: 
+                Not Before: Oct 24 22:00:00 2001 GMT, Not After: Oct 24 22:00:00 2013 GMT
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            X509v3 Subject Key Identifier: 
+                33:0B:A0:66:D1:EA:DA:CE:DE:62:93:04:28:52:B5:14:7F:38:68:B7
+    Signature Algorithm: sha1WithRSAEncryption
+        47:73:fe:8d:27:54:f0:f5:d4:77:9c:27:79:57:57:b7:15:56:
+        ec:c7:d8:58:b7:01:02:f4:33:ed:93:50:88:9e:7c:46:b1:bd:
+        3f:14:6f:f1:b3:47:48:8b:8c:97:06:d7:ea:7e:a3:5c:2a:bb:
+        4d:2f:47:e2:f8:39:06:c9:9c:2e:31:1a:03:78:f4:bc:38:c6:
+        22:8b:33:31:f0:16:04:04:7d:f9:76:e4:4b:d7:c0:e6:83:ec:
+        59:cc:3f:de:ff:4f:6b:b7:67:7e:a6:86:81:32:23:03:9d:c8:
+        f7:5f:c1:4a:60:a5:92:a9:b1:a4:a0:60:c3:78:87:b3:22:f3:
+        2a:eb:5b:a9:ed:05:ab:37:0f:b1:e2:d3:95:76:63:56:74:8c:
+        58:72:1b:37:e5:64:a1:be:4d:0c:93:98:0c:97:f6:87:6d:b3:
+        3f:e7:cb:80:a6:ed:88:c7:5f:50:62:02:e8:99:74:16:d0:e6:
+        b4:39:f1:27:cb:c8:40:d6:e3:86:10:a9:23:12:92:e0:69:41:
+        63:a7:af:25:0b:c0:c5:92:cb:1e:98:a3:5a:ba:c5:33:0f:a0:
+        97:01:dd:7f:e0:7b:d6:06:54:cf:a1:e2:4d:38:eb:4b:50:b5:
+        cb:26:f4:ca:da:70:4a:6a:a1:e2:79:aa:e1:a7:33:f6:fd:4a:
+        1f:f6:d9:60
+SHA1 Fingerprint=A9:62:8F:4B:98:A9:1B:48:35:BA:D2:C1:46:32:86:BB:66:64:6A:8C
+-----BEGIN CERTIFICATE-----
+MIIEVzCCAz+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnTELMAkGA1UEBhMCRVMx
+IjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1
+dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2
+MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20w
+HhcNMDExMDI0MjIwMDAwWhcNMTMxMDI0MjIwMDAwWjCBnTELMAkGA1UEBhMCRVMx
+IjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1
+dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2
+MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20w
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDnIwNvbyOlXnjOlSztlB5u
+Cp4Bx+ow0Syd3Tfom5h5VtP8c9/Qit5Vj1H5WuretXDE7aTt/6MNbg9kUDGvASdY
+rv5sp0ovFy3Tc9UTHI9ZpTQsHVQERc1ouKDAA6XPhUJHlShbz++AbOCQl4oBPB3z
+hxAwJkh91/zpnZFx/0GaqUC1N5wpIE8fUuOgfRNtVLcK3ulqTgesrBlf3H5idPay
+BQC6haD9HThuy1q7hryUZzM1gywfI834yJFxzJeL764P3CkDG8A563DtwW4O2GcL
+iam8NeTvtjS0pbbELaW+0MOUJEjb35bTALVmGotmBQ/dPz/LP6pemkr4tErvlTcb
+AgMBAAGjgZ8wgZwwKgYDVR0RBCMwIYYfaHR0cDovL3d3dy5maXJtYXByb2Zlc2lv
+bmFsLmNvbTASBgNVHRMBAf8ECDAGAQH/AgEBMCsGA1UdEAQkMCKADzIwMDExMDI0
+MjIwMDAwWoEPMjAxMzEwMjQyMjAwMDBaMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4E
+FgQUMwugZtHq2s7eYpMEKFK1FH84aLcwDQYJKoZIhvcNAQEFBQADggEBAEdz/o0n
+VPD11HecJ3lXV7cVVuzH2Fi3AQL0M+2TUIiefEaxvT8Ub/GzR0iLjJcG1+p+o1wq
+u00vR+L4OQbJnC4xGgN49Lw4xiKLMzHwFgQEffl25EvXwOaD7FnMP97/T2u3Z36m
+hoEyIwOdyPdfwUpgpZKpsaSgYMN4h7Mi8yrrW6ntBas3D7Hi05V2Y1Z0jFhyGzfl
+ZKG+TQyTmAyX9odtsz/ny4Cm7YjHX1BiAuiZdBbQ5rQ58SfLyEDW44YQqSMSkuBp
+QWOnryULwMWSyx6Yo1q6xTMPoJcB3X/ge9YGVM+h4k0460tQtcsm9MracEpqoeJ5
+quGnM/b9Sh/22WA=
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/17b51fe6.0 b/libcore/security/src/main/files/cacerts/17b51fe6.0
new file mode 100644
index 0000000..c5b47b1
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/17b51fe6.0
@@ -0,0 +1,85 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            85:bd:4b:f3:d8:da:e3:69:f6:94:d7:5f:c3:a5:44:23
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=FR, O=Certplus, CN=Class 2 Primary CA
+        Validity
+            Not Before: Jul  7 17:05:00 1999 GMT
+            Not After : Jul  6 23:59:59 2019 GMT
+        Subject: C=FR, O=Certplus, CN=Class 2 Primary CA
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:dc:50:96:d0:12:f8:35:d2:08:78:7a:b6:52:70:
+                    fd:6f:ee:cf:b9:11:cb:5d:77:e1:ec:e9:7e:04:8d:
+                    d6:cc:6f:73:43:57:60:ac:33:0a:44:ec:03:5f:1c:
+                    80:24:91:e5:a8:91:56:12:82:f7:e0:2b:f4:db:ae:
+                    61:2e:89:10:8d:6b:6c:ba:b3:02:bd:d5:36:c5:48:
+                    37:23:e2:f0:5a:37:52:33:17:12:e2:d1:60:4d:be:
+                    2f:41:11:e3:f6:17:25:0c:8b:91:c0:1b:99:7b:99:
+                    56:0d:af:ee:d2:bc:47:57:e3:79:49:7b:34:89:27:
+                    24:84:de:b1:ec:e9:58:4e:fe:4e:df:5a:be:41:ad:
+                    ac:08:c5:18:0e:ef:d2:53:ee:6c:d0:9d:12:01:13:
+                    8d:dc:80:62:f7:95:a9:44:88:4a:71:4e:60:55:9e:
+                    db:23:19:79:56:07:0c:3f:63:0b:5c:b0:e2:be:7e:
+                    15:fc:94:33:58:41:38:74:c4:e1:8f:8b:df:26:ac:
+                    1f:b5:8b:3b:b7:43:59:6b:b0:24:a6:6d:90:8b:c4:
+                    72:ea:5d:33:98:b7:cb:de:5e:7b:ef:94:f1:1b:3e:
+                    ca:c9:21:c1:c5:98:02:aa:a2:f6:5b:77:9b:f5:7e:
+                    96:55:34:1c:67:69:c0:f1:42:e3:47:ac:fc:28:1c:
+                    66:55
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:TRUE, pathlen:10
+            X509v3 Key Usage: 
+                Certificate Sign, CRL Sign
+            X509v3 Subject Key Identifier: 
+                E3:73:2D:DF:CB:0E:28:0C:DE:DD:B3:A4:CA:79:B8:8E:BB:E8:30:89
+            Netscape Cert Type: 
+                SSL CA, S/MIME CA
+            X509v3 CRL Distribution Points: 
+                URI:http://www.certplus.com/CRL/class2.crl
+
+    Signature Algorithm: sha1WithRSAEncryption
+        a7:54:cf:88:44:19:cb:df:d4:7f:00:df:56:33:62:b5:f7:51:
+        01:90:eb:c3:3f:d1:88:44:e9:24:5d:ef:e7:14:bd:20:b7:9a:
+        3c:00:fe:6d:9f:db:90:dc:d7:f4:62:d6:8b:70:5d:e7:e5:04:
+        48:a9:68:7c:c9:f1:42:f3:6c:7f:c5:7a:7c:1d:51:88:ba:d2:
+        0a:3e:27:5d:de:2d:51:4e:d3:13:64:69:e4:2e:e3:d3:e7:9b:
+        09:99:a6:e0:95:9b:ce:1a:d7:7f:be:3c:ce:52:b3:11:15:c1:
+        0f:17:cd:03:bb:9c:25:15:ba:a2:76:89:fc:06:f1:18:d0:93:
+        4b:0e:7c:82:b7:a5:f4:f6:5f:fe:ed:40:a6:9d:84:74:39:b9:
+        dc:1e:85:16:da:29:1b:86:23:00:c9:bb:89:7e:6e:80:88:1e:
+        2f:14:b4:03:24:a8:32:6f:03:9a:47:2c:30:be:56:c6:a7:42:
+        02:70:1b:ea:40:d8:ba:05:03:70:07:a4:96:ff:fd:48:33:0a:
+        e1:dc:a5:81:90:9b:4d:dd:7d:e7:e7:b2:cd:5c:c8:6a:95:f8:
+        a5:f6:8d:c4:5d:78:08:be:7b:06:d6:49:cf:19:36:50:23:2e:
+        08:e6:9e:05:4d:47:18:d5:16:e9:b1:d6:b6:10:d5:bb:97:bf:
+        a2:8e:b4:54
+SHA1 Fingerprint=74:20:74:41:72:9C:DD:92:EC:79:31:D8:23:10:8D:C2:81:92:E2:BB
+-----BEGIN CERTIFICATE-----
+MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw
+PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz
+cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9
+MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz
+IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ
+ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR
+VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL
+kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd
+EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas
+H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0
+HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud
+DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4
+QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu
+Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/
+AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8
+yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR
+FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA
+ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB
+kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7
+l7+ijrRU
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/1dac3003.0 b/libcore/security/src/main/files/cacerts/1dac3003.0
new file mode 100644
index 0000000..6f7dd03
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/1dac3003.0
@@ -0,0 +1,28 @@
+
+subject=/C=US/O=Digital Signature Trust/OU=DST ACES/CN=DST ACES CA X6
+issuer=/C=US/O=Digital Signature Trust/OU=DST ACES/CN=DST ACES CA X6
+-----BEGIN CERTIFICATE-----
+MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBb
+MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3Qx
+ETAPBgNVBAsTCERTVCBBQ0VTMRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0w
+MzExMjAyMTE5NThaFw0xNzExMjAyMTE5NThaMFsxCzAJBgNVBAYTAlVTMSAwHgYD
+VQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UECxMIRFNUIEFDRVMx
+FzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPu
+ktKe1jzIDZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7
+gLFViYsx+tC3dr5BPTCapCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZH
+fAjIgrrep4c9oW24MFbCswKBXy314powGCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4a
+ahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPyMjwmR/onJALJfh1biEIT
+ajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1UdEwEB/wQF
+MAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rk
+c3QuY29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjto
+dHRwOi8vd3d3LnRydXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMt
+aW5kZXguaHRtbDAdBgNVHQ4EFgQUCXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZI
+hvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V25FYrnJmQ6AgwbN99Pe7lv7Uk
+QIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6tFr8hlxCBPeP/
+h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq
+nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpR
+rscL9yuwNwXsvFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf2
+9w4LTJxoeHtxMcfrHuBnQfO3oKfN5XozNmr6mis=
+-----END CERTIFICATE-----
+
diff --git a/libcore/security/src/main/files/cacerts/1dbdda5b.0 b/libcore/security/src/main/files/cacerts/1dbdda5b.0
new file mode 100644
index 0000000..fe4a54b
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/1dbdda5b.0
@@ -0,0 +1,22 @@
+
+subject=/C=ES/O=FNMT/OU=FNMT Clase 2 CA
+issuer=/C=ES/O=FNMT/OU=FNMT Clase 2 CA
+-----BEGIN CERTIFICATE-----
+MIIC+TCCAmKgAwIBAgIENvEbGTANBgkqhkiG9w0BAQUFADA2MQswCQYDVQQGEwJF
+UzENMAsGA1UEChMERk5NVDEYMBYGA1UECxMPRk5NVCBDbGFzZSAyIENBMB4XDTk5
+MDMxODE0NTYxOVoXDTE5MDMxODE1MjYxOVowNjELMAkGA1UEBhMCRVMxDTALBgNV
+BAoTBEZOTVQxGDAWBgNVBAsTD0ZOTVQgQ2xhc2UgMiBDQTCBnTANBgkqhkiG9w0B
+AQEFAAOBiwAwgYcCgYEAmD+tGTaTPT7+dkIU/TVv8fqtInpY40bQXcZa+WItjzFe
+/rQw/lB0rNadHeBixkndFBJ9cQusBsE/1waH4JCJ1uXjA7LyJ7GfM8iqazZKo8Q/
+eUGdiUYvKz5j1DhWkaodsQ1CdU3zh07jD03MtGy/YhOH6tCbjrbi/xn0lAnVlmEC
+AQOjggEUMIIBEDARBglghkgBhvhCAQEEBAMCAAcwWAYDVR0fBFEwTzBNoEugSaRH
+MEUxCzAJBgNVBAYTAkVTMQ0wCwYDVQQKEwRGTk1UMRgwFgYDVQQLEw9GTk1UIENs
+YXNlIDIgQ0ExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5OTAzMTgxNDU2
+MTlagQ8yMDE5MDMxODE0NTYxOVowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFECa
+dkSXdAfErBTLHo1POkV8MNdhMB0GA1UdDgQWBBRAmnZEl3QHxKwUyx6NTzpFfDDX
+YTAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG
+SIb3DQEBBQUAA4GBAGFMoHxZY1tm+O5lE85DgEe5sjXJyITHa3NgReSdN531jiW5
++aqqyuP4Q5wvoIkFsUUylCoeA41dpt7PV5Xa3yZgX8vflR64zgjY+IrJT6lodZPj
+LwVMZGACokIeb4ZoZVUO2ENv8pExPqNHPCgFr0W2nSJMJntLfVsV+RlG3whd
+-----END CERTIFICATE-----
+
diff --git a/libcore/security/src/main/files/cacerts/1dcd6f4c.0 b/libcore/security/src/main/files/cacerts/1dcd6f4c.0
new file mode 100644
index 0000000..a428f8b
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/1dcd6f4c.0
@@ -0,0 +1,121 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            1f:9d:59:5a:d7:2f:c2:06:44:a5:80:08:69:e3:5e:f6
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=TW, O=Government Root Certification Authority
+        Validity
+            Not Before: Dec  5 13:23:33 2002 GMT
+            Not After : Dec  5 13:23:33 2032 GMT
+        Subject: C=TW, O=Government Root Certification Authority
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (4096 bit)
+                Modulus (4096 bit):
+                    00:9a:25:b8:ec:cc:a2:75:a8:7b:f7:ce:5b:59:8a:
+                    c9:d1:86:12:08:54:ec:9c:f2:e7:46:f6:88:f3:7c:
+                    e9:a5:df:4c:47:36:a4:1b:01:1c:7f:1e:57:8a:8d:
+                    c3:c5:d1:21:e3:da:24:3f:48:2b:fb:9f:2e:a1:94:
+                    e7:2c:1c:93:d1:bf:1b:01:87:53:99:ce:a7:f5:0a:
+                    21:76:77:ff:a9:b7:c6:73:94:4f:46:f7:10:49:37:
+                    fa:a8:59:49:5d:6a:81:07:56:f2:8a:f9:06:d0:f7:
+                    70:22:4d:b4:b7:41:b9:32:b8:b1:f0:b1:c3:9c:3f:
+                    70:fd:53:dd:81:aa:d8:63:78:f6:d8:53:6e:a1:ac:
+                    6a:84:24:72:54:86:c6:d2:b2:ca:1c:0e:79:81:d6:
+                    b5:70:62:08:01:2e:4e:4f:0e:d5:11:af:a9:af:e5:
+                    9a:bf:dc:cc:87:6d:26:e4:c9:57:a2:fb:96:f9:cc:
+                    e1:3f:53:8c:6c:4c:7e:9b:53:08:0b:6c:17:fb:67:
+                    c8:c2:ad:b1:cd:80:b4:97:dc:76:01:16:15:e9:6a:
+                    d7:a4:e1:78:47:ce:86:d5:fb:31:f3:fa:31:be:34:
+                    aa:28:fb:70:4c:1d:49:c7:af:2c:9d:6d:66:a6:b6:
+                    8d:64:7e:b5:20:6a:9d:3b:81:b6:8f:40:00:67:4b:
+                    89:86:b8:cc:65:fe:15:53:e9:04:c1:d6:5f:1d:44:
+                    d7:0a:2f:27:9a:46:7d:a1:0d:75:ad:54:86:15:dc:
+                    49:3b:f1:96:ce:0f:9b:a0:ec:a3:7a:5d:be:d5:2a:
+                    75:42:e5:7b:de:a5:b6:aa:af:28:ac:ac:90:ac:38:
+                    b7:d5:68:35:26:7a:dc:f7:3b:f3:fd:45:9b:d1:bb:
+                    43:78:6e:6f:f1:42:54:6a:98:f0:0d:ad:97:e9:52:
+                    5e:e9:d5:6a:72:de:6a:f7:1b:60:14:f4:a5:e4:b6:
+                    71:67:aa:1f:ea:e2:4d:c1:42:40:fe:67:46:17:38:
+                    2f:47:3f:71:9c:ae:e5:21:ca:61:2d:6d:07:a8:84:
+                    7c:2d:ee:51:25:f1:63:90:9e:fd:e1:57:88:6b:ef:
+                    8a:23:6d:b1:e6:bd:3f:ad:d1:3d:96:0b:85:8d:cd:
+                    6b:27:bb:b7:05:9b:ec:bb:91:a9:0a:07:12:02:97:
+                    4e:20:90:f0:ff:0d:1e:e2:41:3b:d3:40:3a:e7:8d:
+                    5d:da:66:e4:02:b0:07:52:98:5c:0e:8e:33:9c:c2:
+                    a6:95:fb:55:19:6e:4c:8e:ae:4b:0f:bd:c1:38:4d:
+                    5e:8f:84:1d:66:cd:c5:60:96:b4:52:5a:05:89:8e:
+                    95:7a:98:c1:91:3c:95:23:b2:0e:f4:79:b4:c9:7c:
+                    c1:4a:21
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                CC:CC:EF:CC:29:60:A4:3B:B1:92:B6:3C:FA:32:62:8F:AC:25:15:3B
+            X509v3 Basic Constraints: 
+                CA:TRUE
+            setCext-hashedRoot: 
+                0/0-...0...+......0...g*........"...(6....2.1:.Qe
+    Signature Algorithm: sha1WithRSAEncryption
+        40:80:4a:fa:26:c9:ce:5e:30:dd:4f:86:74:76:58:f5:ae:b3:
+        83:33:78:a4:7a:74:17:19:4e:e9:52:b5:b9:e0:0a:74:62:aa:
+        68:ca:78:a0:4c:9a:8e:2c:23:2e:d5:6a:12:24:bf:d4:68:d3:
+        8a:d0:d8:9c:9f:b4:1f:0c:de:38:7e:57:38:fc:8d:e2:4f:5e:
+        0c:9f:ab:3b:d2:ff:75:97:cb:a4:e3:67:08:ff:e5:c0:16:b5:
+        48:01:7d:e9:f9:0a:ff:1b:e5:6a:69:bf:78:21:a8:c2:a7:23:
+        a9:86:ab:76:56:e8:0e:0c:f6:13:dd:2a:66:8a:64:49:3d:1a:
+        18:87:90:04:9f:42:52:b7:4f:cb:fe:47:41:76:35:ef:ff:00:
+        76:36:45:32:9b:c6:46:85:5d:e2:24:b0:1e:e3:48:96:98:57:
+        47:94:55:7a:0f:41:b1:44:24:f3:c1:fe:1a:6b:bf:88:fd:c1:
+        a6:da:93:60:5e:81:4a:99:20:9c:48:66:19:b5:00:79:54:0f:
+        b8:2c:2f:4b:bc:a9:5d:5b:60:7f:8c:87:a5:e0:52:63:2a:be:
+        d8:3b:85:40:15:fe:1e:b6:65:3f:c5:4b:da:7e:b5:7a:35:29:
+        a3:2e:7a:98:60:22:a3:f4:7d:27:4e:2d:ea:b4:74:3c:e9:0f:
+        a4:33:0f:10:11:bc:13:01:d6:e5:0e:d3:bf:b5:12:a2:e1:45:
+        23:c0:cc:08:6e:61:b7:89:ab:83:e3:24:1e:e6:5d:07:e7:1f:
+        20:3e:cf:67:c8:e7:ac:30:6d:27:4b:68:6e:4b:2a:5c:02:08:
+        34:db:f8:76:e4:67:a3:26:9c:3f:a2:32:c2:4a:c5:81:18:31:
+        10:56:aa:84:ef:2d:0a:ff:b8:1f:77:d2:bf:a5:58:a0:62:e4:
+        d7:4b:91:75:8d:89:80:98:7e:6d:cb:53:4e:5e:af:f6:b2:97:
+        85:97:b9:da:55:06:b9:24:ee:d7:c6:38:1e:63:1b:12:3b:95:
+        e1:58:ac:f2:df:84:d5:5f:99:2f:0d:55:5b:e6:38:db:2e:3f:
+        72:e9:48:85:cb:bb:29:13:8f:1e:38:55:b9:f3:b2:c4:30:99:
+        23:4e:5d:f2:48:a1:12:0c:dc:12:90:09:90:54:91:03:3c:47:
+        e5:d5:c9:65:e0:b7:4b:7d:ec:47:d3:b3:0b:3e:ad:9e:d0:74:
+        00:0e:eb:bd:51:ad:c0:de:2c:c0:c3:6a:fe:ef:dc:0b:a7:fa:
+        46:df:60:db:9c:a6:59:50:75:23:69:73:93:b2:f9:fc:02:d3:
+        47:e6:71:ce:10:02:ee:27:8c:84:ff:ac:45:0d:13:5c:83:32:
+        e0:25:a5:86:2c:7c:f4:12
+SHA1 Fingerprint=F4:8B:11:BF:DE:AB:BE:94:54:20:71:E6:41:DE:6B:BE:88:2B:40:B9
+-----BEGIN CERTIFICATE-----
+MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/
+MQswCQYDVQQGEwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5MB4XDTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1ow
+PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp
+Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
+AJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qNw8XR
+IePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1q
+gQdW8or5BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKy
+yhwOeYHWtXBiCAEuTk8O1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAts
+F/tnyMKtsc2AtJfcdgEWFelq16TheEfOhtX7MfP6Mb40qij7cEwdScevLJ1tZqa2
+jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wovJ5pGfaENda1UhhXcSTvx
+ls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7Q3hub/FC
+VGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHK
+YS1tB6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoH
+EgKXTiCQ8P8NHuJBO9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThN
+Xo+EHWbNxWCWtFJaBYmOlXqYwZE8lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1Ud
+DgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNVHRMEBTADAQH/MDkGBGcqBwAE
+MTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg209yewDL7MTqK
+UWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ
+TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyf
+qzvS/3WXy6TjZwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaK
+ZEk9GhiHkASfQlK3T8v+R0F2Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFE
+JPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlUD7gsL0u8qV1bYH+Mh6XgUmMqvtg7
+hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6QzDxARvBMB1uUO07+1
+EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+HbkZ6Mm
+nD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WX
+udpVBrkk7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44Vbnz
+ssQwmSNOXfJIoRIM3BKQCZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDe
+LMDDav7v3Aun+kbfYNucpllQdSNpc5Oy+fwC00fmcc4QAu4njIT/rEUNE1yDMuAl
+pYYsfPQS
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/219d9499.0 b/libcore/security/src/main/files/cacerts/219d9499.0
new file mode 100644
index 0000000..688288a
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/219d9499.0
@@ -0,0 +1,84 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 0 (0x0)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=US, O=The Go Daddy Group, Inc., OU=Go Daddy Class 2 Certification Authority
+        Validity
+            Not Before: Jun 29 17:06:20 2004 GMT
+            Not After : Jun 29 17:06:20 2034 GMT
+        Subject: C=US, O=The Go Daddy Group, Inc., OU=Go Daddy Class 2 Certification Authority
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:de:9d:d7:ea:57:18:49:a1:5b:eb:d7:5f:48:86:
+                    ea:be:dd:ff:e4:ef:67:1c:f4:65:68:b3:57:71:a0:
+                    5e:77:bb:ed:9b:49:e9:70:80:3d:56:18:63:08:6f:
+                    da:f2:cc:d0:3f:7f:02:54:22:54:10:d8:b2:81:d4:
+                    c0:75:3d:4b:7f:c7:77:c3:3e:78:ab:1a:03:b5:20:
+                    6b:2f:6a:2b:b1:c5:88:7e:c4:bb:1e:b0:c1:d8:45:
+                    27:6f:aa:37:58:f7:87:26:d7:d8:2d:f6:a9:17:b7:
+                    1f:72:36:4e:a6:17:3f:65:98:92:db:2a:6e:5d:a2:
+                    fe:88:e0:0b:de:7f:e5:8d:15:e1:eb:cb:3a:d5:e2:
+                    12:a2:13:2d:d8:8e:af:5f:12:3d:a0:08:05:08:b6:
+                    5c:a5:65:38:04:45:99:1e:a3:60:60:74:c5:41:a5:
+                    72:62:1b:62:c5:1f:6f:5f:1a:42:be:02:51:65:a8:
+                    ae:23:18:6a:fc:78:03:a9:4d:7f:80:c3:fa:ab:5a:
+                    fc:a1:40:a4:ca:19:16:fe:b2:c8:ef:5e:73:0d:ee:
+                    77:bd:9a:f6:79:98:bc:b1:07:67:a2:15:0d:dd:a0:
+                    58:c6:44:7b:0a:3e:62:28:5f:ba:41:07:53:58:cf:
+                    11:7e:38:74:c5:f8:ff:b5:69:90:8f:84:74:ea:97:
+                    1b:af
+                Exponent: 3 (0x3)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                D2:C4:B0:D2:91:D4:4C:11:71:B3:61:CB:3D:A1:FE:DD:A8:6A:D4:E3
+            X509v3 Authority Key Identifier: 
+                keyid:D2:C4:B0:D2:91:D4:4C:11:71:B3:61:CB:3D:A1:FE:DD:A8:6A:D4:E3
+                DirName:/C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority
+                serial:00
+
+            X509v3 Basic Constraints: 
+                CA:TRUE
+    Signature Algorithm: sha1WithRSAEncryption
+        32:4b:f3:b2:ca:3e:91:fc:12:c6:a1:07:8c:8e:77:a0:33:06:
+        14:5c:90:1e:18:f7:08:a6:3d:0a:19:f9:87:80:11:6e:69:e4:
+        96:17:30:ff:34:91:63:72:38:ee:cc:1c:01:a3:1d:94:28:a4:
+        31:f6:7a:c4:54:d7:f6:e5:31:58:03:a2:cc:ce:62:db:94:45:
+        73:b5:bf:45:c9:24:b5:d5:82:02:ad:23:79:69:8d:b8:b6:4d:
+        ce:cf:4c:ca:33:23:e8:1c:88:aa:9d:8b:41:6e:16:c9:20:e5:
+        89:9e:cd:3b:da:70:f7:7e:99:26:20:14:54:25:ab:6e:73:85:
+        e6:9b:21:9d:0a:6c:82:0e:a8:f8:c2:0c:fa:10:1e:6c:96:ef:
+        87:0d:c4:0f:61:8b:ad:ee:83:2b:95:f8:8e:92:84:72:39:eb:
+        20:ea:83:ed:83:cd:97:6e:08:bc:eb:4e:26:b6:73:2b:e4:d3:
+        f6:4c:fe:26:71:e2:61:11:74:4a:ff:57:1a:87:0f:75:48:2e:
+        cf:51:69:17:a0:02:12:61:95:d5:d1:40:b2:10:4c:ee:c4:ac:
+        10:43:a6:a5:9e:0a:d5:95:62:9a:0d:cf:88:82:c5:32:0c:e4:
+        2b:9f:45:e6:0d:9f:28:9c:b1:b9:2a:5a:57:ad:37:0f:af:1d:
+        7f:db:bd:9f
+SHA1 Fingerprint=27:96:BA:E6:3F:18:01:E2:77:26:1B:A0:D7:77:70:02:8F:20:EE:E4
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
+MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
+YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
+MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
+ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
+MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
+ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
+PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
+wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
+EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
+avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
+sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
+/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
+IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
+ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
+OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
+TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
+HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
+dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
+ReYNnyicsbkqWletNw+vHX/bvZ8=
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/23f4c490.0 b/libcore/security/src/main/files/cacerts/23f4c490.0
new file mode 100644
index 0000000..8327a4e
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/23f4c490.0
@@ -0,0 +1,84 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 0 (0x0)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=US, O=Starfield Technologies, Inc., OU=Starfield Class 2 Certification Authority
+        Validity
+            Not Before: Jun 29 17:39:16 2004 GMT
+            Not After : Jun 29 17:39:16 2034 GMT
+        Subject: C=US, O=Starfield Technologies, Inc., OU=Starfield Class 2 Certification Authority
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:b7:32:c8:fe:e9:71:a6:04:85:ad:0c:11:64:df:
+                    ce:4d:ef:c8:03:18:87:3f:a1:ab:fb:3c:a6:9f:f0:
+                    c3:a1:da:d4:d8:6e:2b:53:90:fb:24:a4:3e:84:f0:
+                    9e:e8:5f:ec:e5:27:44:f5:28:a6:3f:7b:de:e0:2a:
+                    f0:c8:af:53:2f:9e:ca:05:01:93:1e:8f:66:1c:39:
+                    a7:4d:fa:5a:b6:73:04:25:66:eb:77:7f:e7:59:c6:
+                    4a:99:25:14:54:eb:26:c7:f3:7f:19:d5:30:70:8f:
+                    af:b0:46:2a:ff:ad:eb:29:ed:d7:9f:aa:04:87:a3:
+                    d4:f9:89:a5:34:5f:db:43:91:82:36:d9:66:3c:b1:
+                    b8:b9:82:fd:9c:3a:3e:10:c8:3b:ef:06:65:66:7a:
+                    9b:19:18:3d:ff:71:51:3c:30:2e:5f:be:3d:77:73:
+                    b2:5d:06:6c:c3:23:56:9a:2b:85:26:92:1c:a7:02:
+                    b3:e4:3f:0d:af:08:79:82:b8:36:3d:ea:9c:d3:35:
+                    b3:bc:69:ca:f5:cc:9d:e8:fd:64:8d:17:80:33:6e:
+                    5e:4a:5d:99:c9:1e:87:b4:9d:1a:c0:d5:6e:13:35:
+                    23:5e:df:9b:5f:3d:ef:d6:f7:76:c2:ea:3e:bb:78:
+                    0d:1c:42:67:6b:04:d8:f8:d6:da:6f:8b:f2:44:a0:
+                    01:ab
+                Exponent: 3 (0x3)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                BF:5F:B7:D1:CE:DD:1F:86:F4:5B:55:AC:DC:D7:10:C2:0E:A9:88:E7
+            X509v3 Authority Key Identifier: 
+                keyid:BF:5F:B7:D1:CE:DD:1F:86:F4:5B:55:AC:DC:D7:10:C2:0E:A9:88:E7
+                DirName:/C=US/O=Starfield Technologies, Inc./OU=Starfield Class 2 Certification Authority
+                serial:00
+
+            X509v3 Basic Constraints: 
+                CA:TRUE
+    Signature Algorithm: sha1WithRSAEncryption
+        05:9d:3f:88:9d:d1:c9:1a:55:a1:ac:69:f3:f3:59:da:9b:01:
+        87:1a:4f:57:a9:a1:79:09:2a:db:f7:2f:b2:1e:cc:c7:5e:6a:
+        d8:83:87:a1:97:ef:49:35:3e:77:06:41:58:62:bf:8e:58:b8:
+        0a:67:3f:ec:b3:dd:21:66:1f:c9:54:fa:72:cc:3d:4c:40:d8:
+        81:af:77:9e:83:7a:bb:a2:c7:f5:34:17:8e:d9:11:40:f4:fc:
+        2c:2a:4d:15:7f:a7:62:5d:2e:25:d3:00:0b:20:1a:1d:68:f9:
+        17:b8:f4:bd:8b:ed:28:59:dd:4d:16:8b:17:83:c8:b2:65:c7:
+        2d:7a:a5:aa:bc:53:86:6d:dd:57:a4:ca:f8:20:41:0b:68:f0:
+        f4:fb:74:be:56:5d:7a:79:f5:f9:1d:85:e3:2d:95:be:f5:71:
+        90:43:cc:8d:1f:9a:00:0a:87:29:e9:55:22:58:00:23:ea:e3:
+        12:43:29:5b:47:08:dd:8c:41:6a:65:06:a8:e5:21:aa:41:b4:
+        95:21:95:b9:7d:d1:34:ab:13:d6:ad:bc:dc:e2:3d:39:cd:bd:
+        3e:75:70:a1:18:59:03:c9:22:b4:8f:9c:d5:5e:2a:d7:a5:b6:
+        d4:0a:6d:f8:b7:40:11:46:9a:1f:79:0e:62:bf:0f:97:ec:e0:
+        2f:1f:17:94
+SHA1 Fingerprint=AD:7E:1C:28:B0:64:EF:8F:60:03:40:20:14:C3:D0:E3:37:0E:B5:8A
+-----BEGIN CERTIFICATE-----
+MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
+MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
+U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
+NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE
+ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp
+ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3
+DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf
+8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN
++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0
+X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa
+K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA
+1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G
+A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR
+zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0
+YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
+bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w
+DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3
+L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D
+eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
+xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
+VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
+WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/256fd83b.0 b/libcore/security/src/main/files/cacerts/256fd83b.0
new file mode 100644
index 0000000..39ef065
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/256fd83b.0
@@ -0,0 +1,63 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1002 (0x3ea)
+        Signature Algorithm: md5WithRSAEncryption
+        Issuer: C=DE, ST=Hamburg, L=Hamburg, O=TC TrustCenter for Security in Data Networks GmbH, OU=TC TrustCenter Class 2 CA/emailAddress=certificate@trustcenter.de
+        Validity
+            Not Before: Mar  9 11:59:59 1998 GMT
+            Not After : Jan  1 11:59:59 2011 GMT
+        Subject: C=DE, ST=Hamburg, L=Hamburg, O=TC TrustCenter for Security in Data Networks GmbH, OU=TC TrustCenter Class 2 CA/emailAddress=certificate@trustcenter.de
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:da:38:e8:ed:32:00:29:71:83:01:0d:bf:8c:01:
+                    dc:da:c6:ad:39:a4:a9:8a:2f:d5:8b:5c:68:5f:50:
+                    c6:62:f5:66:bd:ca:91:22:ec:aa:1d:51:d7:3d:b3:
+                    51:b2:83:4e:5d:cb:49:b0:f0:4c:55:e5:6b:2d:c7:
+                    85:0b:30:1c:92:4e:82:d4:ca:02:ed:f7:6f:be:dc:
+                    e0:e3:14:b8:05:53:f2:9a:f4:56:8b:5a:9e:85:93:
+                    d1:b4:82:56:ae:4d:bb:a8:4b:57:16:bc:fe:f8:58:
+                    9e:f8:29:8d:b0:7b:cd:78:c9:4f:ac:8b:67:0c:f1:
+                    9c:fb:fc:57:9b:57:5c:4f:0d
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            X509v3 Key Usage: critical
+                Digital Signature, Certificate Sign, CRL Sign
+            Netscape CA Policy Url: 
+                http://www.trustcenter.de/guidelines
+            Netscape Cert Type: 
+                SSL CA, S/MIME CA, Object Signing CA
+    Signature Algorithm: md5WithRSAEncryption
+        84:52:fb:28:df:ff:1f:75:01:bc:01:be:04:56:97:6a:74:42:
+        24:31:83:f9:46:b1:06:8a:89:cf:96:2c:33:bf:8c:b5:5f:7a:
+        72:a1:85:06:ce:86:f8:05:8e:e8:f9:25:ca:da:83:8c:06:ac:
+        eb:36:6d:85:91:34:04:36:f4:42:f0:f8:79:2e:0a:48:5c:ab:
+        cc:51:4f:78:76:a0:d9:ac:19:bd:2a:d1:69:04:28:91:ca:36:
+        10:27:80:57:5b:d2:5c:f5:c2:5b:ab:64:81:63:74:51:f4:97:
+        bf:cd:12:28:f7:4d:66:7f:a7:f0:1c:01:26:78:b2:66:47:70:
+        51:64
+SHA1 Fingerprint=83:8E:30:F7:7F:DD:14:AA:38:5E:D1:45:00:9C:0E:22:36:49:4F:AA
+-----BEGIN CERTIFICATE-----
+MIIDXDCCAsWgAwIBAgICA+owDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRF
+MRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFU
+QyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJI
+MSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAyIENBMSkwJwYJKoZIhvcN
+AQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05ODAzMDkxMTU5NTla
+Fw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVy
+ZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9y
+IFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1
+c3RDZW50ZXIgQ2xhc3MgMiBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVA
+dHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANo46O0y
+AClxgwENv4wB3NrGrTmkqYov1YtcaF9QxmL1Zr3KkSLsqh1R1z2zUbKDTl3LSbDw
+TFXlay3HhQswHJJOgtTKAu33b77c4OMUuAVT8pr0VotanoWT0bSCVq5Nu6hLVxa8
+/vhYnvgpjbB7zXjJT6yLZwzxnPv8V5tXXE8NAgMBAAGjazBpMA8GA1UdEwEB/wQF
+MAMBAf8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3
+LnRydXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G
+CSqGSIb3DQEBBAUAA4GBAIRS+yjf/x91AbwBvgRWl2p0QiQxg/lGsQaKic+WLDO/
+jLVfenKhhQbOhvgFjuj5Jcrag4wGrOs2bYWRNAQ29ELw+HkuCkhcq8xRT3h2oNms
+Gb0q0WkEKJHKNhAngFdb0lz1wlurZIFjdFH0l7/NEij3TWZ/p/AcASZ4smZHcFFk
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/3c58f906.0 b/libcore/security/src/main/files/cacerts/3c58f906.0
new file mode 100644
index 0000000..7500443
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/3c58f906.0
@@ -0,0 +1,87 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=SE, O=AddTrust AB, OU=AddTrust External TTP Network, CN=AddTrust External CA Root
+        Validity
+            Not Before: May 30 10:48:38 2000 GMT
+            Not After : May 30 10:48:38 2020 GMT
+        Subject: C=SE, O=AddTrust AB, OU=AddTrust External TTP Network, CN=AddTrust External CA Root
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:b7:f7:1a:33:e6:f2:00:04:2d:39:e0:4e:5b:ed:
+                    1f:bc:6c:0f:cd:b5:fa:23:b6:ce:de:9b:11:33:97:
+                    a4:29:4c:7d:93:9f:bd:4a:bc:93:ed:03:1a:e3:8f:
+                    cf:e5:6d:50:5a:d6:97:29:94:5a:80:b0:49:7a:db:
+                    2e:95:fd:b8:ca:bf:37:38:2d:1e:3e:91:41:ad:70:
+                    56:c7:f0:4f:3f:e8:32:9e:74:ca:c8:90:54:e9:c6:
+                    5f:0f:78:9d:9a:40:3c:0e:ac:61:aa:5e:14:8f:9e:
+                    87:a1:6a:50:dc:d7:9a:4e:af:05:b3:a6:71:94:9c:
+                    71:b3:50:60:0a:c7:13:9d:38:07:86:02:a8:e9:a8:
+                    69:26:18:90:ab:4c:b0:4f:23:ab:3a:4f:84:d8:df:
+                    ce:9f:e1:69:6f:bb:d7:42:d7:6b:44:e4:c7:ad:ee:
+                    6d:41:5f:72:5a:71:08:37:b3:79:65:a4:59:a0:94:
+                    37:f7:00:2f:0d:c2:92:72:da:d0:38:72:db:14:a8:
+                    45:c4:5d:2a:7d:b7:b4:d6:c4:ee:ac:cd:13:44:b7:
+                    c9:2b:dd:43:00:25:fa:61:b9:69:6a:58:23:11:b7:
+                    a7:33:8f:56:75:59:f5:cd:29:d7:46:b7:0a:2b:65:
+                    b6:d3:42:6f:15:b2:b8:7b:fb:ef:e9:5d:53:d5:34:
+                    5a:27
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                AD:BD:98:7A:34:B4:26:F7:FA:C4:26:54:EF:03:BD:E0:24:CB:54:1A
+            X509v3 Key Usage: 
+                Certificate Sign, CRL Sign
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            X509v3 Authority Key Identifier: 
+                keyid:AD:BD:98:7A:34:B4:26:F7:FA:C4:26:54:EF:03:BD:E0:24:CB:54:1A
+                DirName:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
+                serial:01
+
+    Signature Algorithm: sha1WithRSAEncryption
+        b0:9b:e0:85:25:c2:d6:23:e2:0f:96:06:92:9d:41:98:9c:d9:
+        84:79:81:d9:1e:5b:14:07:23:36:65:8f:b0:d8:77:bb:ac:41:
+        6c:47:60:83:51:b0:f9:32:3d:e7:fc:f6:26:13:c7:80:16:a5:
+        bf:5a:fc:87:cf:78:79:89:21:9a:e2:4c:07:0a:86:35:bc:f2:
+        de:51:c4:d2:96:b7:dc:7e:4e:ee:70:fd:1c:39:eb:0c:02:51:
+        14:2d:8e:bd:16:e0:c1:df:46:75:e7:24:ad:ec:f4:42:b4:85:
+        93:70:10:67:ba:9d:06:35:4a:18:d3:2b:7a:cc:51:42:a1:7a:
+        63:d1:e6:bb:a1:c5:2b:c2:36:be:13:0d:e6:bd:63:7e:79:7b:
+        a7:09:0d:40:ab:6a:dd:8f:8a:c3:f6:f6:8c:1a:42:05:51:d4:
+        45:f5:9f:a7:62:21:68:15:20:43:3c:99:e7:7c:bd:24:d8:a9:
+        91:17:73:88:3f:56:1b:31:38:18:b4:71:0f:9a:cd:c8:0e:9e:
+        8e:2e:1b:e1:8c:98:83:cb:1f:31:f1:44:4c:c6:04:73:49:76:
+        60:0f:c7:f8:bd:17:80:6b:2e:e9:cc:4c:0e:5a:9a:79:0f:20:
+        0a:2e:d5:9e:63:26:1e:55:92:94:d8:82:17:5a:7b:d0:bc:c7:
+        8f:4e:86:04
+SHA1 Fingerprint=02:FA:F3:E2:91:43:54:68:60:78:57:69:4D:F5:E4:5B:68:85:18:68
+-----BEGIN CERTIFICATE-----
+MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
+IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
+MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
+FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
+bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
+H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
+uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
+mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
+a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
+E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
+WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
+VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
+Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
+cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
+IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
+AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
+YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
+6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
+Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
+c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
+mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/4d654d1d.0 b/libcore/security/src/main/files/cacerts/4d654d1d.0
new file mode 100644
index 0000000..94ed383
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/4d654d1d.0
@@ -0,0 +1,49 @@
+Certificate:
+    Data:
+        Version: 1 (0x0)
+        Serial Number: 421 (0x1a5)
+        Signature Algorithm: md5WithRSAEncryption
+        Issuer: C=US, O=GTE Corporation, OU=GTE CyberTrust Solutions, Inc., CN=GTE CyberTrust Global Root
+        Validity
+            Not Before: Aug 13 00:29:00 1998 GMT
+            Not After : Aug 13 23:59:00 2018 GMT
+        Subject: C=US, O=GTE Corporation, OU=GTE CyberTrust Solutions, Inc., CN=GTE CyberTrust Global Root
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:95:0f:a0:b6:f0:50:9c:e8:7a:c7:88:cd:dd:17:
+                    0e:2e:b0:94:d0:1b:3d:0e:f6:94:c0:8a:94:c7:06:
+                    c8:90:97:c8:b8:64:1a:7a:7e:6c:3c:53:e1:37:28:
+                    73:60:7f:b2:97:53:07:9f:53:f9:6d:58:94:d2:af:
+                    8d:6d:88:67:80:e6:ed:b2:95:cf:72:31:ca:a5:1c:
+                    72:ba:5c:02:e7:64:42:e7:f9:a9:2c:d6:3a:0d:ac:
+                    8d:42:aa:24:01:39:e6:9c:3f:01:85:57:0d:58:87:
+                    45:f8:d3:85:aa:93:69:26:85:70:48:80:3f:12:15:
+                    c7:79:b4:1f:05:2f:3b:62:99
+                Exponent: 65537 (0x10001)
+    Signature Algorithm: md5WithRSAEncryption
+        6d:eb:1b:09:e9:5e:d9:51:db:67:22:61:a4:2a:3c:48:77:e3:
+        a0:7c:a6:de:73:a2:14:03:85:3d:fb:ab:0e:30:c5:83:16:33:
+        81:13:08:9e:7b:34:4e:df:40:c8:74:d7:b9:7d:dc:f4:76:55:
+        7d:9b:63:54:18:e9:f0:ea:f3:5c:b1:d9:8b:42:1e:b9:c0:95:
+        4e:ba:fa:d5:e2:7c:f5:68:61:bf:8e:ec:05:97:5f:5b:b0:d7:
+        a3:85:34:c4:24:a7:0d:0f:95:93:ef:cb:94:d8:9e:1f:9d:5c:
+        85:6d:c7:aa:ae:4f:1f:22:b5:cd:95:ad:ba:a7:cc:f9:ab:0b:
+        7a:7f
+SHA1 Fingerprint=97:81:79:50:D8:1C:96:70:CC:34:D8:09:CF:79:44:31:36:7E:F4:74
+-----BEGIN CERTIFICATE-----
+MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYD
+VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv
+bHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJv
+b3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJV
+UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU
+cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds
+b2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrH
+iM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTS
+r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4
+04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r
+GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9
+3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P
+lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/4e18c148.0 b/libcore/security/src/main/files/cacerts/4e18c148.0
new file mode 100644
index 0000000..be68fd6
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/4e18c148.0
@@ -0,0 +1,26 @@
+
+subject=/C=DE/O=Deutsche Telekom AG/OU=T-TeleSec Trust Center/CN=Deutsche Telekom Root CA 2
+issuer=/C=DE/O=Deutsche Telekom AG/OU=T-TeleSec Trust Center/CN=Deutsche Telekom Root CA 2
+-----BEGIN CERTIFICATE-----
+MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEc
+MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2Vj
+IFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENB
+IDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5MjM1OTAwWjBxMQswCQYDVQQGEwJE
+RTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxl
+U2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290
+IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEU
+ha88EOQ5bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhC
+QN/Po7qCWWqSG6wcmtoIKyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1Mjwr
+rFDa1sPeg5TKqAyZMg4ISFZbavva4VhYAUlfckE8FQYBjl2tqriTtM2e66foai1S
+NNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aKSe5TBY8ZTNXeWHmb0moc
+QqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTVjlsB9WoH
+txa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAP
+BgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC
+AQEAlGRZrTlk5ynrE/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756Abrsp
+tJh6sTtU6zkXR34ajgv8HzFZMQSyzhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpa
+IzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juwzTkZmDLl
+6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4Gdyd1Lx+4ivn+
+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU
+Cm26OWMohpLzGITY+9HPBVZkVw==
+-----END CERTIFICATE-----
+
diff --git a/libcore/security/src/main/files/cacerts/4fbd6bfa.0 b/libcore/security/src/main/files/cacerts/4fbd6bfa.0
new file mode 100644
index 0000000..988dd3c
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/4fbd6bfa.0
@@ -0,0 +1,89 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            44:be:0c:8b:50:00:21:b4:11:d3:2a:68:06:a9:ad:69
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=US, ST=UT, L=Salt Lake City, O=The USERTRUST Network, OU=http://www.usertrust.com, CN=UTN - DATACorp SGC
+        Validity
+            Not Before: Jun 24 18:57:21 1999 GMT
+            Not After : Jun 24 19:06:30 2019 GMT
+        Subject: C=US, ST=UT, L=Salt Lake City, O=The USERTRUST Network, OU=http://www.usertrust.com, CN=UTN - DATACorp SGC
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:df:ee:58:10:a2:2b:6e:55:c4:8e:bf:2e:46:09:
+                    e7:e0:08:0f:2e:2b:7a:13:94:1b:bd:f6:b6:80:8e:
+                    65:05:93:00:1e:bc:af:e2:0f:8e:19:0d:12:47:ec:
+                    ac:ad:a3:fa:2e:70:f8:de:6e:fb:56:42:15:9e:2e:
+                    5c:ef:23:de:21:b9:05:76:27:19:0f:4f:d6:c3:9c:
+                    b4:be:94:19:63:f2:a6:11:0a:eb:53:48:9c:be:f2:
+                    29:3b:16:e8:1a:a0:4c:a6:c9:f4:18:59:68:c0:70:
+                    f2:53:00:c0:5e:50:82:a5:56:6f:36:f9:4a:e0:44:
+                    86:a0:4d:4e:d6:47:6e:49:4a:cb:67:d7:a6:c4:05:
+                    b9:8e:1e:f4:fc:ff:cd:e7:36:e0:9c:05:6c:b2:33:
+                    22:15:d0:b4:e0:cc:17:c0:b2:c0:f4:fe:32:3f:29:
+                    2a:95:7b:d8:f2:a7:4e:0f:54:7c:a1:0d:80:b3:09:
+                    03:c1:ff:5c:dd:5e:9a:3e:bc:ae:bc:47:8a:6a:ae:
+                    71:ca:1f:b1:2a:b8:5f:42:05:0b:ec:46:30:d1:72:
+                    0b:ca:e9:56:6d:f5:ef:df:78:be:61:ba:b2:a5:ae:
+                    04:4c:bc:a8:ac:69:15:97:bd:ef:eb:b4:8c:bf:35:
+                    f8:d4:c3:d1:28:0e:5c:3a:9f:70:18:33:20:77:c4:
+                    a2:af
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Key Usage: 
+                Digital Signature, Non Repudiation, Certificate Sign, CRL Sign
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            X509v3 Subject Key Identifier: 
+                53:32:D1:B3:CF:7F:FA:E0:F1:A0:5D:85:4E:92:D2:9E:45:1D:B4:4F
+            X509v3 CRL Distribution Points: 
+                URI:http://crl.usertrust.com/UTN-DATACorpSGC.crl
+
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication, Microsoft Server Gated Crypto, Netscape Server Gated Crypto
+    Signature Algorithm: sha1WithRSAEncryption
+        27:35:97:00:8a:8b:28:bd:c6:33:30:1e:29:fc:e2:f7:d5:98:
+        d4:40:bb:60:ca:bf:ab:17:2c:09:36:7f:50:fa:41:dc:ae:96:
+        3a:0a:23:3e:89:59:c9:a3:07:ed:1b:37:ad:fc:7c:be:51:49:
+        5a:de:3a:0a:54:08:16:45:c2:99:b1:87:cd:8c:68:e0:69:03:
+        e9:c4:4e:98:b2:3b:8c:16:b3:0e:a0:0c:98:50:9b:93:a9:70:
+        09:c8:2c:a3:8f:df:02:e4:e0:71:3a:f1:b4:23:72:a0:aa:01:
+        df:df:98:3e:14:50:a0:31:26:bd:28:e9:5a:30:26:75:f9:7b:
+        60:1c:8d:f3:cd:50:26:6d:04:27:9a:df:d5:0d:45:47:29:6b:
+        2c:e6:76:d9:a9:29:7d:32:dd:c9:36:3c:bd:ae:35:f1:11:9e:
+        1d:bb:90:3f:12:47:4e:8e:d7:7e:0f:62:73:1d:52:26:38:1c:
+        18:49:fd:30:74:9a:c4:e5:22:2f:d8:c0:8d:ed:91:7a:4c:00:
+        8f:72:7f:5d:da:dd:1b:8b:45:6b:e7:dd:69:97:a8:c5:56:4c:
+        0f:0c:f6:9f:7a:91:37:f6:97:82:e0:dd:71:69:ff:76:3f:60:
+        4d:3c:cf:f7:99:f9:c6:57:f4:c9:55:39:78:ba:2c:79:c9:a6:
+        88:2b:f4:08
+SHA1 Fingerprint=58:11:9F:0E:12:82:87:EA:50:FD:D9:87:45:6F:4F:78:DC:FA:D6:D4
+-----BEGIN CERTIFICATE-----
+MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB
+kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw
+IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG
+EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD
+VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu
+dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6
+E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ
+D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK
+4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq
+lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW
+bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB
+o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT
+MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js
+LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr
+BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB
+AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft
+Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj
+j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH
+KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv
+2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3
+mfnGV/TJVTl4uix5yaaIK/QI
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/54edfa5d.0 b/libcore/security/src/main/files/cacerts/54edfa5d.0
new file mode 100644
index 0000000..e2530a4
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/54edfa5d.0
@@ -0,0 +1,63 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1003 (0x3eb)
+        Signature Algorithm: md5WithRSAEncryption
+        Issuer: C=DE, ST=Hamburg, L=Hamburg, O=TC TrustCenter for Security in Data Networks GmbH, OU=TC TrustCenter Class 3 CA/emailAddress=certificate@trustcenter.de
+        Validity
+            Not Before: Mar  9 11:59:59 1998 GMT
+            Not After : Jan  1 11:59:59 2011 GMT
+        Subject: C=DE, ST=Hamburg, L=Hamburg, O=TC TrustCenter for Security in Data Networks GmbH, OU=TC TrustCenter Class 3 CA/emailAddress=certificate@trustcenter.de
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:b6:b4:c1:35:05:2e:0d:8d:ec:a0:40:6a:1c:0e:
+                    27:a6:50:92:6b:50:1b:07:de:2e:e7:76:cc:e0:da:
+                    fc:84:a8:5e:8c:63:6a:2b:4d:d9:4e:02:76:11:c1:
+                    0b:f2:8d:79:ca:00:b6:f1:b0:0e:d7:fb:a4:17:3d:
+                    af:ab:69:7a:96:27:bf:af:33:a1:9a:2a:59:aa:c4:
+                    b5:37:08:f2:12:a5:31:b6:43:f5:32:96:71:28:28:
+                    ab:8d:28:86:df:bb:ee:e3:0c:7d:30:d6:c3:52:ab:
+                    8f:5d:27:9c:6b:c0:a3:e7:05:6b:57:49:44:b3:6e:
+                    ea:64:cf:d2:8e:7a:50:77:77
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            X509v3 Key Usage: critical
+                Digital Signature, Certificate Sign, CRL Sign
+            Netscape CA Policy Url: 
+                http://www.trustcenter.de/guidelines
+            Netscape Cert Type: 
+                SSL CA, S/MIME CA, Object Signing CA
+    Signature Algorithm: md5WithRSAEncryption
+        16:3d:c6:cd:c1:bb:85:71:85:46:9f:3e:20:8f:51:28:99:ec:
+        2d:45:21:63:23:5b:04:bb:4c:90:b8:88:92:04:4d:bd:7d:01:
+        a3:3f:f6:ec:ce:f1:de:fe:7d:e5:e1:3e:bb:c6:ab:5e:0b:dd:
+        3d:96:c4:cb:a9:d4:f9:26:e6:06:4e:9e:0c:a5:7a:ba:6e:c3:
+        7c:82:19:d1:c7:b1:b1:c3:db:0d:8e:9b:40:7c:37:0b:f1:5d:
+        e8:fd:1f:90:88:a5:0e:4e:37:64:21:a8:4e:8d:b4:9f:f1:de:
+        48:ad:d5:56:18:52:29:8b:47:34:12:09:d4:bb:92:35:ef:0f:
+        db:34
+SHA1 Fingerprint=9F:C7:96:E8:F8:52:4F:86:3A:E1:49:6D:38:12:42:10:5F:1B:78:F5
+-----BEGIN CERTIFICATE-----
+MIIDXDCCAsWgAwIBAgICA+swDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRF
+MRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFU
+QyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJI
+MSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAzIENBMSkwJwYJKoZIhvcN
+AQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05ODAzMDkxMTU5NTla
+Fw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVy
+ZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9y
+IFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1
+c3RDZW50ZXIgQ2xhc3MgMyBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVA
+dHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALa0wTUF
+Lg2N7KBAahwOJ6ZQkmtQGwfeLud2zODa/ISoXoxjaitN2U4CdhHBC/KNecoAtvGw
+Dtf7pBc9r6tpepYnv68zoZoqWarEtTcI8hKlMbZD9TKWcSgoq40oht+77uMMfTDW
+w1Krj10nnGvAo+cFa1dJRLNu6mTP0o56UHd3AgMBAAGjazBpMA8GA1UdEwEB/wQF
+MAMBAf8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3
+LnRydXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G
+CSqGSIb3DQEBBAUAA4GBABY9xs3Bu4VxhUafPiCPUSiZ7C1FIWMjWwS7TJC4iJIE
+Tb19AaM/9uzO8d7+feXhPrvGq14L3T2WxMup1Pkm5gZOngylerpuw3yCGdHHsbHD
+2w2Om0B8NwvxXej9H5CIpQ5ON2QhqE6NtJ/x3kit1VYYUimLRzQSCdS7kjXvD9s0
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/594f1775.0 b/libcore/security/src/main/files/cacerts/594f1775.0
new file mode 100644
index 0000000..1c7d3b0
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/594f1775.0
@@ -0,0 +1,70 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 903804111 (0x35def4cf)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=US, O=Equifax, OU=Equifax Secure Certificate Authority
+        Validity
+            Not Before: Aug 22 16:41:51 1998 GMT
+            Not After : Aug 22 16:41:51 2018 GMT
+        Subject: C=US, O=Equifax, OU=Equifax Secure Certificate Authority
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:c1:5d:b1:58:67:08:62:ee:a0:9a:2d:1f:08:6d:
+                    91:14:68:98:0a:1e:fe:da:04:6f:13:84:62:21:c3:
+                    d1:7c:ce:9f:05:e0:b8:01:f0:4e:34:ec:e2:8a:95:
+                    04:64:ac:f1:6b:53:5f:05:b3:cb:67:80:bf:42:02:
+                    8e:fe:dd:01:09:ec:e1:00:14:4f:fc:fb:f0:0c:dd:
+                    43:ba:5b:2b:e1:1f:80:70:99:15:57:93:16:f1:0f:
+                    97:6a:b7:c2:68:23:1c:cc:4d:59:30:ac:51:1e:3b:
+                    af:2b:d6:ee:63:45:7b:c5:d9:5f:50:d2:e3:50:0f:
+                    3a:88:e7:bf:14:fd:e0:c7:b9
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 CRL Distribution Points: 
+                DirName:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority/CN=CRL1
+
+            X509v3 Private Key Usage Period: 
+                Not After: Aug 22 16:41:51 2018 GMT
+            X509v3 Key Usage: 
+                Certificate Sign, CRL Sign
+            X509v3 Authority Key Identifier: 
+                keyid:48:E6:68:F9:2B:D2:B2:95:D7:47:D8:23:20:10:4F:33:98:90:9F:D4
+
+            X509v3 Subject Key Identifier: 
+                48:E6:68:F9:2B:D2:B2:95:D7:47:D8:23:20:10:4F:33:98:90:9F:D4
+            X509v3 Basic Constraints: 
+                CA:TRUE
+            1.2.840.113533.7.65.0: 
+                0...V3.0c....
+    Signature Algorithm: sha1WithRSAEncryption
+        58:ce:29:ea:fc:f7:de:b5:ce:02:b9:17:b5:85:d1:b9:e3:e0:
+        95:cc:25:31:0d:00:a6:92:6e:7f:b6:92:63:9e:50:95:d1:9a:
+        6f:e4:11:de:63:85:6e:98:ee:a8:ff:5a:c8:d3:55:b2:66:71:
+        57:de:c0:21:eb:3d:2a:a7:23:49:01:04:86:42:7b:fc:ee:7f:
+        a2:16:52:b5:67:67:d3:40:db:3b:26:58:b2:28:77:3d:ae:14:
+        77:61:d6:fa:2a:66:27:a0:0d:fa:a7:73:5c:ea:70:f1:94:21:
+        65:44:5f:fa:fc:ef:29:68:a9:a2:87:79:ef:79:ef:4f:ac:07:
+        77:38
+SHA1 Fingerprint=D2:32:09:AD:23:D3:14:23:21:74:E4:0D:7F:9D:62:13:97:86:63:3A
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
+UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
+dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1
+MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx
+dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f
+BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A
+cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC
+AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ
+MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm
+aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw
+ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj
+IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF
+MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
+A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
+7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
+1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/5a5372fc.0 b/libcore/security/src/main/files/cacerts/5a5372fc.0
new file mode 100644
index 0000000..fe74cd5
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/5a5372fc.0
@@ -0,0 +1,74 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 105 (0x69)
+        Signature Algorithm: md5WithRSAEncryption
+        Issuer: C=HU, L=Budapest, O=NetLock Halozatbiztonsagi Kft., OU=Tanusitvanykiadok, CN=NetLock Uzleti (Class B) Tanusitvanykiado
+        Validity
+            Not Before: Feb 25 14:10:22 1999 GMT
+            Not After : Feb 20 14:10:22 2019 GMT
+        Subject: C=HU, L=Budapest, O=NetLock Halozatbiztonsagi Kft., OU=Tanusitvanykiadok, CN=NetLock Uzleti (Class B) Tanusitvanykiado
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:b1:ea:04:ec:20:a0:23:c2:8f:38:60:cf:c7:46:
+                    b3:d5:1b:fe:fb:b9:99:9e:04:dc:1c:7f:8c:4a:81:
+                    98:ee:a4:d4:ca:8a:17:b9:22:7f:83:0a:75:4c:9b:
+                    c0:69:d8:64:39:a3:ed:92:a3:fd:5b:5c:74:1a:c0:
+                    47:ca:3a:69:76:9a:ba:e2:44:17:fc:4c:a3:d5:fe:
+                    b8:97:88:af:88:03:89:1f:a4:f2:04:3e:c8:07:0b:
+                    e6:f9:b3:2f:7a:62:14:09:46:14:ca:64:f5:8b:80:
+                    b5:62:a8:d8:6b:d6:71:93:2d:b3:bf:09:54:58:ed:
+                    06:eb:a8:7b:dc:43:b1:a1:69
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:TRUE, pathlen:4
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            Netscape Cert Type: 
+                SSL CA, S/MIME CA, Object Signing CA
+            Netscape Comment: 
+                FIGYELEM! Ezen tanusitvany a NetLock Kft. Altalanos Szolgaltatasi Felteteleiben leirt eljarasok alapjan keszult. A hitelesites folyamatat a NetLock Kft. termekfelelosseg-biztositasa vedi. A digitalis alairas elfogadasanak feltetele az eloirt ellenorzesi eljaras megtetele. Az eljaras leirasa megtalalhato a NetLock Kft. Internet honlapjan a https://www.netlock.net/docs cimen vagy kerheto az ellenorzes@netlock.net e-mail cimen. IMPORTANT! The issuance and the use of this certificate is subject to the NetLock CPS available at https://www.netlock.net/docs or by e-mail at cps@netlock.net.
+    Signature Algorithm: md5WithRSAEncryption
+        04:db:ae:8c:17:af:f8:0e:90:31:4e:cd:3e:09:c0:6d:3a:b0:
+        f8:33:4c:47:4c:e3:75:88:10:97:ac:b0:38:15:91:c6:29:96:
+        cc:21:c0:6d:3c:a5:74:cf:d8:82:a5:39:c3:65:e3:42:70:bb:
+        22:90:e3:7d:db:35:76:e1:a0:b5:da:9f:70:6e:93:1a:30:39:
+        1d:30:db:2e:e3:7c:b2:91:b2:d1:37:29:fa:b9:d6:17:5c:47:
+        4f:e3:1d:38:eb:9f:d5:7b:95:a8:28:9e:15:4a:d1:d1:d0:2b:
+        00:97:a0:e2:92:36:2b:63:ac:58:01:6b:33:29:50:86:83:f1:
+        01:48
+SHA1 Fingerprint=87:9F:4B:EE:05:DF:98:58:3B:E3:60:D6:33:E7:0D:3F:FE:98:71:AF
+-----BEGIN CERTIFICATE-----
+MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUx
+ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0
+b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQD
+EylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikgVGFudXNpdHZhbnlraWFkbzAeFw05
+OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYDVQQGEwJIVTERMA8G
+A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh
+Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5l
+dExvY2sgVXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqG
+SIb3DQEBAQUAA4GNADCBiQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xK
+gZjupNTKihe5In+DCnVMm8Bp2GQ5o+2So/1bXHQawEfKOml2mrriRBf8TKPV/riX
+iK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr1nGTLbO/CVRY7QbrqHvc
+Q7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8E
+BAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1G
+SUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFu
+b3MgU3pvbGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBh
+bGFwamFuIGtlc3p1bHQuIEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExv
+Y2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGln
+aXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0
+IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh
+c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGph
+biBhIGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJo
+ZXRvIGF6IGVsbGVub3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBP
+UlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmlj
+YXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBo
+dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNA
+bmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06
+sPgzTEdM43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXa
+n3BukxowOR0w2y7jfLKRstE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKS
+NitjrFgBazMpUIaD8QFI
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/635ccfd5.0 b/libcore/security/src/main/files/cacerts/635ccfd5.0
new file mode 100644
index 0000000..b69711b
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/635ccfd5.0
@@ -0,0 +1,74 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 104 (0x68)
+        Signature Algorithm: md5WithRSAEncryption
+        Issuer: C=HU, L=Budapest, O=NetLock Halozatbiztonsagi Kft., OU=Tanusitvanykiadok, CN=NetLock Expressz (Class C) Tanusitvanykiado
+        Validity
+            Not Before: Feb 25 14:08:11 1999 GMT
+            Not After : Feb 20 14:08:11 2019 GMT
+        Subject: C=HU, L=Budapest, O=NetLock Halozatbiztonsagi Kft., OU=Tanusitvanykiadok, CN=NetLock Expressz (Class C) Tanusitvanykiado
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:eb:ec:b0:6c:61:8a:23:25:af:60:20:e3:d9:9f:
+                    fc:93:0b:db:5d:8d:b0:a1:b3:40:3a:82:ce:fd:75:
+                    e0:78:32:03:86:5a:86:95:91:ed:53:fa:9d:40:fc:
+                    e6:e8:dd:d9:5b:7a:03:bd:5d:f3:3b:0c:c3:51:79:
+                    9b:ad:55:a0:e9:d0:03:10:af:0a:ba:14:42:d9:52:
+                    26:11:22:c7:d2:20:cc:82:a4:9a:a9:fe:b8:81:76:
+                    9d:6a:b7:d2:36:75:3e:b1:86:09:f6:6e:6d:7e:4e:
+                    b7:7a:ec:ae:71:84:f6:04:33:08:25:32:eb:74:ac:
+                    16:44:c6:e4:40:93:1d:7f:ad
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:TRUE, pathlen:4
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            Netscape Cert Type: 
+                SSL CA, S/MIME CA, Object Signing CA
+            Netscape Comment: 
+                FIGYELEM! Ezen tanusitvany a NetLock Kft. Altalanos Szolgaltatasi Felteteleiben leirt eljarasok alapjan keszult. A hitelesites folyamatat a NetLock Kft. termekfelelosseg-biztositasa vedi. A digitalis alairas elfogadasanak feltetele az eloirt ellenorzesi eljaras megtetele. Az eljaras leirasa megtalalhato a NetLock Kft. Internet honlapjan a https://www.netlock.net/docs cimen vagy kerheto az ellenorzes@netlock.net e-mail cimen. IMPORTANT! The issuance and the use of this certificate is subject to the NetLock CPS available at https://www.netlock.net/docs or by e-mail at cps@netlock.net.
+    Signature Algorithm: md5WithRSAEncryption
+        10:ad:7f:d7:0c:32:80:0a:d8:86:f1:79:98:b5:ad:d4:cd:b3:
+        36:c4:96:48:c1:5c:cd:9a:d9:05:2e:9f:be:50:eb:f4:26:14:
+        10:2d:d4:66:17:f8:9e:c1:27:fd:f1:ed:e4:7b:4b:a0:6c:b5:
+        ab:9a:57:70:a6:ed:a0:a4:ed:2e:f5:fd:fc:bd:fe:4d:37:08:
+        0c:bc:e3:96:83:22:f5:49:1b:7f:4b:2b:b4:54:c1:80:7c:99:
+        4e:1d:d0:8c:ee:d0:ac:e5:92:fa:75:56:fe:64:a0:13:8f:b8:
+        b8:16:9d:61:05:67:80:c8:d0:d8:a5:07:02:34:98:04:8d:33:
+        04:d4
+SHA1 Fingerprint=E3:92:51:2F:0A:CF:F5:05:DF:F6:DE:06:7F:75:37:E1:65:EA:57:4B
+-----BEGIN CERTIFICATE-----
+MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUx
+ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0
+b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQD
+EytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBDKSBUYW51c2l0dmFueWtpYWRvMB4X
+DTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJBgNVBAYTAkhVMREw
+DwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9u
+c2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMr
+TmV0TG9jayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNA
+OoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3ZW3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC
+2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63euyucYT2BDMIJTLrdKwW
+RMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQwDgYDVR0P
+AQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEW
+ggJNRklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0
+YWxhbm9zIFN6b2xnYWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFz
+b2sgYWxhcGphbiBrZXN6dWx0LiBBIGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBO
+ZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1iaXp0b3NpdGFzYSB2ZWRpLiBB
+IGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0ZWxlIGF6IGVs
+b2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs
+ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25s
+YXBqYW4gYSBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kg
+a2VyaGV0byBheiBlbGxlbm9yemVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4g
+SU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5kIHRoZSB1c2Ugb2YgdGhpcyBjZXJ0
+aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQUyBhdmFpbGFibGUg
+YXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwgYXQg
+Y3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmY
+ta3UzbM2xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2g
+pO0u9f38vf5NNwgMvOOWgyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4
+Fp1hBWeAyNDYpQcCNJgEjTME1A==
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/6e8bf996.0 b/libcore/security/src/main/files/cacerts/6e8bf996.0
new file mode 100644
index 0000000..dca7c1e
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/6e8bf996.0
@@ -0,0 +1,72 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 65568 (0x10020)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=PL, O=Unizeto Sp. z o.o., CN=Certum CA
+        Validity
+            Not Before: Jun 11 10:46:39 2002 GMT
+            Not After : Jun 11 10:46:39 2027 GMT
+        Subject: C=PL, O=Unizeto Sp. z o.o., CN=Certum CA
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:ce:b1:c1:2e:d3:4f:7c:cd:25:ce:18:3e:4f:c4:
+                    8c:6f:80:6a:73:c8:5b:51:f8:9b:d2:dc:bb:00:5c:
+                    b1:a0:fc:75:03:ee:81:f0:88:ee:23:52:e9:e6:15:
+                    33:8d:ac:2d:09:c5:76:f9:2b:39:80:89:e4:97:4b:
+                    90:a5:a8:78:f8:73:43:7b:a4:61:b0:d8:58:cc:e1:
+                    6c:66:7e:9c:f3:09:5e:55:63:84:d5:a8:ef:f3:b1:
+                    2e:30:68:b3:c4:3c:d8:ac:6e:8d:99:5a:90:4e:34:
+                    dc:36:9a:8f:81:88:50:b7:6d:96:42:09:f3:d7:95:
+                    83:0d:41:4b:b0:6a:6b:f8:fc:0f:7e:62:9f:67:c4:
+                    ed:26:5f:10:26:0f:08:4f:f0:a4:57:28:ce:8f:b8:
+                    ed:45:f6:6e:ee:25:5d:aa:6e:39:be:e4:93:2f:d9:
+                    47:a0:72:eb:fa:a6:5b:af:ca:53:3f:e2:0e:c6:96:
+                    56:11:6e:f7:e9:66:a9:26:d8:7f:95:53:ed:0a:85:
+                    88:ba:4f:29:a5:42:8c:5e:b6:fc:85:20:00:aa:68:
+                    0b:a1:1a:85:01:9c:c4:46:63:82:88:b6:22:b1:ee:
+                    fe:aa:46:59:7e:cf:35:2c:d5:b6:da:5d:f7:48:33:
+                    14:54:b6:eb:d9:6f:ce:cd:88:d6:ab:1b:da:96:3b:
+                    1d:59
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha1WithRSAEncryption
+        b8:8d:ce:ef:e7:14:ba:cf:ee:b0:44:92:6c:b4:39:3e:a2:84:
+        6e:ad:b8:21:77:d2:d4:77:82:87:e6:20:41:81:ee:e2:f8:11:
+        b7:63:d1:17:37:be:19:76:24:1c:04:1a:4c:eb:3d:aa:67:6f:
+        2d:d4:cd:fe:65:31:70:c5:1b:a6:02:0a:ba:60:7b:6d:58:c2:
+        9a:49:fe:63:32:0b:6b:e3:3a:c0:ac:ab:3b:b0:e8:d3:09:51:
+        8c:10:83:c6:34:e0:c5:2b:e0:1a:b6:60:14:27:6c:32:77:8c:
+        bc:b2:72:98:cf:cd:cc:3f:b9:c8:24:42:14:d6:57:fc:e6:26:
+        43:a9:1d:e5:80:90:ce:03:54:28:3e:f7:3f:d3:f8:4d:ed:6a:
+        0a:3a:93:13:9b:3b:14:23:13:63:9c:3f:d1:87:27:79:e5:4c:
+        51:e3:01:ad:85:5d:1a:3b:b1:d5:73:10:a4:d3:f2:bc:6e:64:
+        f5:5a:56:90:a8:c7:0e:4c:74:0f:2e:71:3b:f7:c8:47:f4:69:
+        6f:15:f2:11:5e:83:1e:9c:7c:52:ae:fd:02:da:12:a8:59:67:
+        18:db:bc:70:dd:9b:b1:69:ed:80:ce:89:40:48:6a:0e:35:ca:
+        29:66:15:21:94:2c:e8:60:2a:9b:85:4a:40:f3:6b:8a:24:ec:
+        06:16:2c:73
+SHA1 Fingerprint=62:52:DC:40:F7:11:43:A2:2F:DE:9E:F7:34:8E:06:42:51:B1:81:18
+-----BEGIN CERTIFICATE-----
+MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/E
+jG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWo
+ePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GI
+ULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapu
+Ob7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg
+AKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7
+HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA
+uI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQa
+TOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTg
+xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q
+CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x
+O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs
+6GAqm4VKQPNriiTsBhYscw==
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/72fa7371.0 b/libcore/security/src/main/files/cacerts/72fa7371.0
new file mode 100644
index 0000000..3dd11b1
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/72fa7371.0
@@ -0,0 +1,54 @@
+Certificate:
+    Data:
+        Version: 1 (0x0)
+        Serial Number:
+            7d:d9:fe:07:cf:a8:1e:b7:10:79:67:fb:a7:89:34:c6
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority - G2, OU=(c) 1998 VeriSign, Inc. - For authorized use only, OU=VeriSign Trust Network
+        Validity
+            Not Before: May 18 00:00:00 1998 GMT
+            Not After : Aug  1 23:59:59 2028 GMT
+        Subject: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority - G2, OU=(c) 1998 VeriSign, Inc. - For authorized use only, OU=VeriSign Trust Network
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:cc:5e:d1:11:5d:5c:69:d0:ab:d3:b9:6a:4c:99:
+                    1f:59:98:30:8e:16:85:20:46:6d:47:3f:d4:85:20:
+                    84:e1:6d:b3:f8:a4:ed:0c:f1:17:0f:3b:f9:a7:f9:
+                    25:d7:c1:cf:84:63:f2:7c:63:cf:a2:47:f2:c6:5b:
+                    33:8e:64:40:04:68:c1:80:b9:64:1c:45:77:c7:d8:
+                    6e:f5:95:29:3c:50:e8:34:d7:78:1f:a8:ba:6d:43:
+                    91:95:8f:45:57:5e:7e:c5:fb:ca:a4:04:eb:ea:97:
+                    37:54:30:6f:bb:01:47:32:33:cd:dc:57:9b:64:69:
+                    61:f8:9b:1d:1c:89:4f:5c:67
+                Exponent: 65537 (0x10001)
+    Signature Algorithm: sha1WithRSAEncryption
+        51:4d:cd:be:5c:cb:98:19:9c:15:b2:01:39:78:2e:4d:0f:67:
+        70:70:99:c6:10:5a:94:a4:53:4d:54:6d:2b:af:0d:5d:40:8b:
+        64:d3:d7:ee:de:56:61:92:5f:a6:c4:1d:10:61:36:d3:2c:27:
+        3c:e8:29:09:b9:11:64:74:cc:b5:73:9f:1c:48:a9:bc:61:01:
+        ee:e2:17:a6:0c:e3:40:08:3b:0e:e7:eb:44:73:2a:9a:f1:69:
+        92:ef:71:14:c3:39:ac:71:a7:91:09:6f:e4:71:06:b3:ba:59:
+        57:26:79:00:f6:f8:0d:a2:33:30:28:d4:aa:58:a0:9d:9d:69:
+        91:fd
+SHA1 Fingerprint=85:37:1C:A6:E5:50:14:3D:CE:28:03:47:1B:DE:3A:09:E8:F8:77:0F
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
+c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
+MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
+emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
+DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
+FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg
+UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
+YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
+MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4
+pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0
+13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID
+AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk
+U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i
+F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY
+oJ2daZH9
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/74c26bd0.0 b/libcore/security/src/main/files/cacerts/74c26bd0.0
new file mode 100644
index 0000000..0307ae7
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/74c26bd0.0
@@ -0,0 +1,60 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+        Signature Algorithm: md5WithRSAEncryption
+        Issuer: C=US, O=Equifax Secure Inc., CN=Equifax Secure Global eBusiness CA-1
+        Validity
+            Not Before: Jun 21 04:00:00 1999 GMT
+            Not After : Jun 21 04:00:00 2020 GMT
+        Subject: C=US, O=Equifax Secure Inc., CN=Equifax Secure Global eBusiness CA-1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:ba:e7:17:90:02:65:b1:34:55:3c:49:c2:51:d5:
+                    df:a7:d1:37:8f:d1:e7:81:73:41:52:60:9b:9d:a1:
+                    17:26:78:ad:c7:b1:e8:26:94:32:b5:de:33:8d:3a:
+                    2f:db:f2:9a:7a:5a:73:98:a3:5c:e9:fb:8a:73:1b:
+                    5c:e7:c3:bf:80:6c:cd:a9:f4:d6:2b:c0:f7:f9:99:
+                    aa:63:a2:b1:47:02:0f:d4:e4:51:3a:12:3c:6c:8a:
+                    5a:54:84:70:db:c1:c5:90:cf:72:45:cb:a8:59:c0:
+                    cd:33:9d:3f:a3:96:eb:85:33:21:1c:3e:1e:3e:60:
+                    6e:76:9c:67:85:c5:c8:c3:61
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            Netscape Cert Type: 
+                SSL CA, S/MIME CA, Object Signing CA
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            X509v3 Authority Key Identifier: 
+                keyid:BE:A8:A0:74:72:50:6B:44:B7:C9:23:D8:FB:A8:FF:B3:57:6B:68:6C
+
+            X509v3 Subject Key Identifier: 
+                BE:A8:A0:74:72:50:6B:44:B7:C9:23:D8:FB:A8:FF:B3:57:6B:68:6C
+    Signature Algorithm: md5WithRSAEncryption
+        30:e2:01:51:aa:c7:ea:5f:da:b9:d0:65:0f:30:d6:3e:da:0d:
+        14:49:6e:91:93:27:14:31:ef:c4:f7:2d:45:f8:ec:c7:bf:a2:
+        41:0d:23:b4:92:f9:19:00:67:bd:01:af:cd:e0:71:fc:5a:cf:
+        64:c4:e0:96:98:d0:a3:40:e2:01:8a:ef:27:07:f1:65:01:8a:
+        44:2d:06:65:75:52:c0:86:10:20:21:5f:6c:6b:0f:6c:ae:09:
+        1c:af:f2:a2:18:34:c4:75:a4:73:1c:f1:8d:dc:ef:ad:f9:b3:
+        76:b4:92:bf:dc:95:10:1e:be:cb:c8:3b:5a:84:60:19:56:94:
+        a9:55
+SHA1 Fingerprint=7E:78:4A:10:1C:82:65:CC:2D:E1:F1:6D:47:B4:40:CA:D9:0A:19:45
+-----BEGIN CERTIFICATE-----
+MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT
+ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw
+MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj
+dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l
+c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC
+UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc
+58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/
+o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH
+MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr
+aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA
+A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA
+Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv
+8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/7651b327.0 b/libcore/security/src/main/files/cacerts/7651b327.0
new file mode 100644
index 0000000..c0cee71
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/7651b327.0
@@ -0,0 +1,49 @@
+Certificate:
+    Data:
+        Version: 1 (0x0)
+        Serial Number:
+            70:ba:e4:1d:10:d9:29:34:b6:38:ca:7b:03:cc:ba:bf
+        Signature Algorithm: md2WithRSAEncryption
+        Issuer: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority
+        Validity
+            Not Before: Jan 29 00:00:00 1996 GMT
+            Not After : Aug  1 23:59:59 2028 GMT
+        Subject: C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:c9:5c:59:9e:f2:1b:8a:01:14:b4:10:df:04:40:
+                    db:e3:57:af:6a:45:40:8f:84:0c:0b:d1:33:d9:d9:
+                    11:cf:ee:02:58:1f:25:f7:2a:a8:44:05:aa:ec:03:
+                    1f:78:7f:9e:93:b9:9a:00:aa:23:7d:d6:ac:85:a2:
+                    63:45:c7:72:27:cc:f4:4c:c6:75:71:d2:39:ef:4f:
+                    42:f0:75:df:0a:90:c6:8e:20:6f:98:0f:f8:ac:23:
+                    5f:70:29:36:a4:c9:86:e7:b1:9a:20:cb:53:a5:85:
+                    e7:3d:be:7d:9a:fe:24:45:33:dc:76:15:ed:0f:a2:
+                    71:64:4c:65:2e:81:68:45:a7
+                Exponent: 65537 (0x10001)
+    Signature Algorithm: md2WithRSAEncryption
+        bb:4c:12:2b:cf:2c:26:00:4f:14:13:dd:a6:fb:fc:0a:11:84:
+        8c:f3:28:1c:67:92:2f:7c:b6:c5:fa:df:f0:e8:95:bc:1d:8f:
+        6c:2c:a8:51:cc:73:d8:a4:c0:53:f0:4e:d6:26:c0:76:01:57:
+        81:92:5e:21:f1:d1:b1:ff:e7:d0:21:58:cd:69:17:e3:44:1c:
+        9c:19:44:39:89:5c:dc:9c:00:0f:56:8d:02:99:ed:a2:90:45:
+        4c:e4:bb:10:a4:3d:f0:32:03:0e:f1:ce:f8:e8:c9:51:8c:e6:
+        62:9f:e6:9f:c0:7d:b7:72:9c:c9:36:3a:6b:9f:4e:a8:ff:64:
+        0d:64
+SHA1 Fingerprint=74:2C:31:92:E6:07:E4:24:EB:45:49:54:2B:E1:BB:C5:3E:61:74:E2
+-----BEGIN CERTIFICATE-----
+MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG
+A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
+cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
+MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
+BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
+YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
+BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
+I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
+CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do
+lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc
+AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/7d3cd826.0 b/libcore/security/src/main/files/cacerts/7d3cd826.0
new file mode 100644
index 0000000..2c128b1
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/7d3cd826.0
@@ -0,0 +1,52 @@
+Certificate:
+    Data:
+        Version: 1 (0x0)
+        Serial Number: 1 (0x1)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: L=ValiCert Validation Network, O=ValiCert, Inc., OU=ValiCert Class 3 Policy Validation Authority, CN=http://www.valicert.com//emailAddress=info@valicert.com
+        Validity
+            Not Before: Jun 26 00:22:33 1999 GMT
+            Not After : Jun 26 00:22:33 2019 GMT
+        Subject: L=ValiCert Validation Network, O=ValiCert, Inc., OU=ValiCert Class 3 Policy Validation Authority, CN=http://www.valicert.com//emailAddress=info@valicert.com
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:e3:98:51:96:1c:e8:d5:b1:06:81:6a:57:c3:72:
+                    75:93:ab:cf:9e:a6:fc:f3:16:52:d6:2d:4d:9f:35:
+                    44:a8:2e:04:4d:07:49:8a:38:29:f5:77:37:e7:b7:
+                    ab:5d:df:36:71:14:99:8f:dc:c2:92:f1:e7:60:92:
+                    97:ec:d8:48:dc:bf:c1:02:20:c6:24:a4:28:4c:30:
+                    5a:76:6d:b1:5c:f3:dd:de:9e:10:71:a1:88:c7:5b:
+                    9b:41:6d:ca:b0:b8:8e:15:ee:ad:33:2b:cf:47:04:
+                    5c:75:71:0a:98:24:98:29:a7:49:59:a5:dd:f8:b7:
+                    43:62:61:f3:d3:e2:d0:55:3f
+                Exponent: 65537 (0x10001)
+    Signature Algorithm: sha1WithRSAEncryption
+        56:bb:02:58:84:67:08:2c:df:1f:db:7b:49:33:f5:d3:67:9d:
+        f4:b4:0a:10:b3:c9:c5:2c:e2:92:6a:71:78:27:f2:70:83:42:
+        d3:3e:cf:a9:54:f4:f1:d8:92:16:8c:d1:04:cb:4b:ab:c9:9f:
+        45:ae:3c:8a:a9:b0:71:33:5d:c8:c5:57:df:af:a8:35:b3:7f:
+        89:87:e9:e8:25:92:b8:7f:85:7a:ae:d6:bc:1e:37:58:2a:67:
+        c9:91:cf:2a:81:3e:ed:c6:39:df:c0:3e:19:9c:19:cc:13:4d:
+        82:41:b5:8c:de:e0:3d:60:08:20:0f:45:7e:6b:a2:7f:a3:8c:
+        15:ee
+SHA1 Fingerprint=69:BD:8C:F4:9C:D3:00:FB:59:2E:17:93:CA:55:6A:F3:EC:AA:35:FB
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMjIzM1oXDTE5MDYy
+NjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfD
+cnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs
+2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqY
+JJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliE
+Zwgs3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJ
+n0WuPIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A
+PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/97b4211c.0 b/libcore/security/src/main/files/cacerts/97b4211c.0
new file mode 100644
index 0000000..9417aed
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/97b4211c.0
@@ -0,0 +1,47 @@
+Certificate:
+    Data:
+        Version: 1 (0x0)
+        Serial Number: 419 (0x1a3)
+        Signature Algorithm: md5WithRSAEncryption
+        Issuer: C=US, O=GTE Corporation, CN=GTE CyberTrust Root
+        Validity
+            Not Before: Feb 23 23:01:00 1996 GMT
+            Not After : Feb 23 23:59:00 2006 GMT
+        Subject: C=US, O=GTE Corporation, CN=GTE CyberTrust Root
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:b8:e6:4f:ba:db:98:7c:71:7c:af:44:b7:d3:0f:
+                    46:d9:64:e5:93:c1:42:8e:c7:ba:49:8d:35:2d:7a:
+                    e7:8b:bd:e5:05:31:59:c6:b1:2f:0a:0c:fb:9f:a7:
+                    3f:a2:09:66:84:56:1e:37:29:1b:87:e9:7e:0c:ca:
+                    9a:9f:a5:7f:f5:15:94:a3:d5:a2:46:82:d8:68:4c:
+                    d1:37:15:06:68:af:bd:f8:b0:b3:f0:29:f5:95:5a:
+                    09:16:61:77:0a:22:25:d4:4f:45:aa:c7:bd:e5:96:
+                    df:f9:d4:a8:8e:42:cc:24:c0:1e:91:27:4a:b5:6d:
+                    06:80:63:39:c4:a2:5e:38:03
+                Exponent: 65537 (0x10001)
+    Signature Algorithm: md5WithRSAEncryption
+        12:b3:75:c6:5f:1d:e1:61:55:80:00:d4:81:4b:7b:31:0f:23:
+        63:e7:3d:f3:03:f9:f4:36:a8:bb:d9:e3:a5:97:4d:ea:2b:29:
+        e0:d6:6a:73:81:e6:c0:89:a3:d3:f1:e0:a5:a5:22:37:9a:63:
+        c2:48:20:b4:db:72:e3:c8:f6:d9:7c:be:b1:af:53:da:14:b4:
+        21:b8:d6:d5:96:e3:fe:4e:0c:59:62:b6:9a:4a:f9:42:dd:8c:
+        6f:81:a9:71:ff:f4:0a:72:6d:6d:44:0e:9d:f3:74:74:a8:d5:
+        34:49:e9:5e:9e:e9:b4:7a:e1:e5:5a:1f:84:30:9c:d3:9f:a5:
+        25:d8
+SHA1 Fingerprint=90:DE:DE:9E:4C:4E:9F:6F:D8:86:17:57:9D:D3:91:BC:65:A6:89:64
+-----BEGIN CERTIFICATE-----
+MIIB+jCCAWMCAgGjMA0GCSqGSIb3DQEBBAUAMEUxCzAJBgNVBAYTAlVTMRgwFgYD
+VQQKEw9HVEUgQ29ycG9yYXRpb24xHDAaBgNVBAMTE0dURSBDeWJlclRydXN0IFJv
+b3QwHhcNOTYwMjIzMjMwMTAwWhcNMDYwMjIzMjM1OTAwWjBFMQswCQYDVQQGEwJV
+UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMRwwGgYDVQQDExNHVEUgQ3liZXJU
+cnVzdCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC45k+625h8cXyv
+RLfTD0bZZOWTwUKOx7pJjTUteueLveUFMVnGsS8KDPufpz+iCWaEVh43KRuH6X4M
+ypqfpX/1FZSj1aJGgthoTNE3FQZor734sLPwKfWVWgkWYXcKIiXUT0Wqx73llt/5
+1KiOQswkwB6RJ0q1bQaAYznEol44AwIDAQABMA0GCSqGSIb3DQEBBAUAA4GBABKz
+dcZfHeFhVYAA1IFLezEPI2PnPfMD+fQ2qLvZ46WXTeorKeDWanOB5sCJo9Px4KWl
+IjeaY8JIILTbcuPI9tl8vrGvU9oUtCG41tWW4/5ODFlitppK+ULdjG+BqXH/9Apy
+bW1EDp3zdHSo1TRJ6V6e6bR64eVaH4QwnNOfpSXY
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/a3896b44.0 b/libcore/security/src/main/files/cacerts/a3896b44.0
new file mode 100644
index 0000000..1dc798e
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/a3896b44.0
@@ -0,0 +1,77 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 0 (0x0)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=JP, O=SECOM Trust.net, OU=Security Communication RootCA1
+        Validity
+            Not Before: Sep 30 04:20:49 2003 GMT
+            Not After : Sep 30 04:20:49 2023 GMT
+        Subject: C=JP, O=SECOM Trust.net, OU=Security Communication RootCA1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:b3:b3:fe:7f:d3:6d:b1:ef:16:7c:57:a5:0c:6d:
+                    76:8a:2f:4b:bf:64:fb:4c:ee:8a:f0:f3:29:7c:f5:
+                    ff:ee:2a:e0:e9:e9:ba:5b:64:22:9a:9a:6f:2c:3a:
+                    26:69:51:05:99:26:dc:d5:1c:6a:71:c6:9a:7d:1e:
+                    9d:dd:7c:6c:c6:8c:67:67:4a:3e:f8:71:b0:19:27:
+                    a9:09:0c:a6:95:bf:4b:8c:0c:fa:55:98:3b:d8:e8:
+                    22:a1:4b:71:38:79:ac:97:92:69:b3:89:7e:ea:21:
+                    68:06:98:14:96:87:d2:61:36:bc:6d:27:56:9e:57:
+                    ee:c0:c0:56:fd:32:cf:a4:d9:8e:c2:23:d7:8d:a8:
+                    f3:d8:25:ac:97:e4:70:38:f4:b6:3a:b4:9d:3b:97:
+                    26:43:a3:a1:bc:49:59:72:4c:23:30:87:01:58:f6:
+                    4e:be:1c:68:56:66:af:cd:41:5d:c8:b3:4d:2a:55:
+                    46:ab:1f:da:1e:e2:40:3d:db:cd:7d:b9:92:80:9c:
+                    37:dd:0c:96:64:9d:dc:22:f7:64:8b:df:61:de:15:
+                    94:52:15:a0:7d:52:c9:4b:a8:21:c9:c6:b1:ed:cb:
+                    c3:95:60:d1:0f:f0:ab:70:f8:df:cb:4d:7e:ec:d6:
+                    fa:ab:d9:bd:7f:54:f2:a5:e9:79:fa:d9:d6:76:24:
+                    28:73
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                A0:73:49:99:68:DC:85:5B:65:E3:9B:28:2F:57:9F:BD:33:BC:07:48
+            X509v3 Key Usage: 
+                Certificate Sign, CRL Sign
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha1WithRSAEncryption
+        68:40:a9:a8:bb:e4:4f:5d:79:b3:05:b5:17:b3:60:13:eb:c6:
+        92:5d:e0:d1:d3:6a:fe:fb:be:9b:6d:bf:c7:05:6d:59:20:c4:
+        1c:f0:b7:da:84:58:02:63:fa:48:16:ef:4f:a5:0b:f7:4a:98:
+        f2:3f:9e:1b:ad:47:6b:63:ce:08:47:eb:52:3f:78:9c:af:4d:
+        ae:f8:d5:4f:cf:9a:98:2a:10:41:39:52:c4:dd:d9:9b:0e:ef:
+        93:01:ae:b2:2e:ca:68:42:24:42:6c:b0:b3:3a:3e:cd:e9:da:
+        48:c4:15:cb:e9:f9:07:0f:92:50:49:8a:dd:31:97:5f:c9:e9:
+        37:aa:3b:59:65:97:94:32:c9:b3:9f:3e:3a:62:58:c5:49:ad:
+        62:0e:71:a5:32:aa:2f:c6:89:76:43:40:13:13:67:3d:a2:54:
+        25:10:cb:f1:3a:f2:d9:fa:db:49:56:bb:a6:fe:a7:41:35:c3:
+        e0:88:61:c9:88:c7:df:36:10:22:98:59:ea:b0:4a:fb:56:16:
+        73:6e:ac:4d:f7:22:a1:4f:ad:1d:7a:2d:45:27:e5:30:c1:5e:
+        f2:da:13:cb:25:42:51:95:47:03:8c:6c:21:cc:74:42:ed:53:
+        ff:33:8b:8f:0f:57:01:16:2f:cf:a6:ee:c9:70:22:14:bd:fd:
+        be:6c:0b:03
+SHA1 Fingerprint=36:B1:2B:49:F9:81:9E:D7:4C:9E:BC:38:0F:C6:56:8F:5D:AC:B2:F7
+-----BEGIN CERTIFICATE-----
+MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY
+MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t
+dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5
+WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD
+VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8
+9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ
+DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9
+Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N
+QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ
+xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G
+A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T
+AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG
+kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr
+Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5
+Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU
+JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot
+RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw==
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/a7605362.0 b/libcore/security/src/main/files/cacerts/a7605362.0
new file mode 100644
index 0000000..a3314fc
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/a7605362.0
@@ -0,0 +1,76 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 29 (0x1d)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=FI, O=Sonera, CN=Sonera Class2 CA
+        Validity
+            Not Before: Apr  6 07:29:40 2001 GMT
+            Not After : Apr  6 07:29:40 2021 GMT
+        Subject: C=FI, O=Sonera, CN=Sonera Class2 CA
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:90:17:4a:35:9d:ca:f0:0d:96:c7:44:fa:16:37:
+                    fc:48:bd:bd:7f:80:2d:35:3b:e1:6f:a8:67:a9:bf:
+                    03:1c:4d:8c:6f:32:47:d5:41:68:a4:13:04:c1:35:
+                    0c:9a:84:43:fc:5c:1d:ff:89:b3:e8:17:18:cd:91:
+                    5f:fb:89:e3:ea:bf:4e:5d:7c:1b:26:d3:75:79:ed:
+                    e6:84:e3:57:e5:ad:29:c4:f4:3a:28:e7:a5:7b:84:
+                    36:69:b3:fd:5e:76:bd:a3:2d:99:d3:90:4e:23:28:
+                    7d:18:63:f1:54:3b:26:9d:76:5b:97:42:b2:ff:ae:
+                    f0:4e:ec:dd:39:95:4e:83:06:7f:e7:49:40:c8:c5:
+                    01:b2:54:5a:66:1d:3d:fc:f9:e9:3c:0a:9e:81:b8:
+                    70:f0:01:8b:e4:23:54:7c:c8:ae:f8:90:1e:00:96:
+                    72:d4:54:cf:61:23:bc:ea:fb:9d:02:95:d1:b6:b9:
+                    71:3a:69:08:3f:0f:b4:e1:42:c7:88:f5:3f:98:a8:
+                    a7:ba:1c:e0:71:71:ef:58:57:81:50:7a:5c:6b:74:
+                    46:0e:83:03:98:c3:8e:a8:6e:f2:76:32:6e:27:83:
+                    c2:73:f3:dc:18:e8:b4:93:ea:75:44:6b:04:60:20:
+                    71:57:87:9d:f3:be:a0:90:23:3d:8a:24:e1:da:21:
+                    db:c3
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            X509v3 Subject Key Identifier: 
+                4A:A0:AA:58:84:D3:5E:3C
+            X509v3 Key Usage: 
+                Certificate Sign, CRL Sign
+    Signature Algorithm: sha1WithRSAEncryption
+        5a:ce:87:f9:16:72:15:57:4b:1d:d9:9b:e7:a2:26:30:ec:93:
+        67:df:d6:2d:d2:34:af:f7:38:a5:ce:ab:16:b9:ab:2f:7c:35:
+        cb:ac:d0:0f:b4:4c:2b:fc:80:ef:6b:8c:91:5f:36:76:f7:db:
+        b3:1b:19:ea:f4:b2:11:fd:61:71:44:bf:28:b3:3a:1d:bf:b3:
+        43:e8:9f:bf:dc:31:08:71:b0:9d:8d:d6:34:47:32:90:c6:65:
+        24:f7:a0:4a:7c:04:73:8f:39:6f:17:8c:72:b5:bd:4b:c8:7a:
+        f8:7b:83:c3:28:4e:9c:09:ea:67:3f:b2:67:04:1b:c3:14:da:
+        f8:e7:49:24:91:d0:1d:6a:fa:61:39:ef:6b:e7:21:75:06:07:
+        d8:12:b4:21:20:70:42:71:81:da:3c:9a:36:be:a6:5b:0d:6a:
+        6c:9a:1f:91:7b:f9:f9:ef:42:ba:4e:4e:9e:cc:0c:8d:94:dc:
+        d9:45:9c:5e:ec:42:50:63:ae:f4:5d:c4:b1:12:dc:ca:3b:a8:
+        2e:9d:14:5a:05:75:b7:ec:d7:63:e2:ba:35:b6:04:08:91:e8:
+        da:9d:9c:f6:66:b5:18:ac:0a:a6:54:26:34:33:d2:1b:c1:d4:
+        7f:1a:3a:8e:0b:aa:32:6e:db:fc:4f:25:9f:d9:32:c7:96:5a:
+        70:ac:df:4c
+SHA1 Fingerprint=37:F7:6D:E6:07:7C:90:C5:B1:3E:93:1A:B7:41:10:B4:F2:E4:9A:27
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP
+MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx
+MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV
+BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o
+Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt
+5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s
+3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej
+vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu
+8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw
+DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG
+MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil
+zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/
+3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD
+FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6
+Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2
+ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/add67345.0 b/libcore/security/src/main/files/cacerts/add67345.0
new file mode 100644
index 0000000..6bc1f89
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/add67345.0
@@ -0,0 +1,96 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 259 (0x103)
+        Signature Algorithm: md5WithRSAEncryption
+        Issuer: C=HU, ST=Hungary, L=Budapest, O=NetLock Halozatbiztonsagi Kft., OU=Tanusitvanykiadok, CN=NetLock Kozjegyzoi (Class A) Tanusitvanykiado
+        Validity
+            Not Before: Feb 24 23:14:47 1999 GMT
+            Not After : Feb 19 23:14:47 2019 GMT
+        Subject: C=HU, ST=Hungary, L=Budapest, O=NetLock Halozatbiztonsagi Kft., OU=Tanusitvanykiadok, CN=NetLock Kozjegyzoi (Class A) Tanusitvanykiado
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:bc:74:8c:0f:bb:4c:f4:37:1e:a9:05:82:d8:e6:
+                    e1:6c:70:ea:78:b5:6e:d1:38:44:0d:a8:83:ce:5d:
+                    d2:d6:d5:81:c5:d4:4b:e7:5b:94:70:26:db:3b:9d:
+                    6a:4c:62:f7:71:f3:64:d6:61:3b:3d:eb:73:a3:37:
+                    d9:cf:ea:8c:92:3b:cd:f7:07:dc:66:74:97:f4:45:
+                    22:dd:f4:5c:e0:bf:6d:f3:be:65:33:e4:15:3a:bf:
+                    db:98:90:55:38:c4:ed:a6:55:63:0b:b0:78:04:f4:
+                    e3:6e:c1:3f:8e:fc:51:78:1f:92:9e:83:c2:fe:d9:
+                    b0:a9:c9:bc:5a:00:ff:a9:a8:98:74:fb:f6:2c:3e:
+                    15:39:0d:b6:04:55:a8:0e:98:20:42:b3:b1:25:ad:
+                    7e:9a:6f:5d:53:b1:ab:0c:fc:eb:e0:f3:7a:b3:a8:
+                    b3:ff:46:f6:63:a2:d8:3a:98:7b:b6:ac:85:ff:b0:
+                    25:4f:74:63:e7:13:07:a5:0a:8f:05:f7:c0:64:6f:
+                    7e:a7:27:80:96:de:d4:2e:86:60:c7:6b:2b:5e:73:
+                    7b:17:e7:91:3f:64:0c:d8:4b:22:34:2b:9b:32:f2:
+                    48:1f:9f:a1:0a:84:7a:e2:c2:ad:97:3d:8e:d5:c1:
+                    f9:56:a3:50:e9:c6:b4:fa:98:a2:ee:95:e6:2a:03:
+                    8c:df
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            X509v3 Basic Constraints: critical
+                CA:TRUE, pathlen:4
+            Netscape Cert Type: 
+                SSL CA, S/MIME CA, Object Signing CA
+            Netscape Comment: 
+                FIGYELEM! Ezen tanusitvany a NetLock Kft. Altalanos Szolgaltatasi Felteteleiben leirt eljarasok alapjan keszult. A hitelesites folyamatat a NetLock Kft. termekfelelosseg-biztositasa vedi. A digitalis alairas elfogadasanak feltetele az eloirt ellenorzesi eljaras megtetele. Az eljaras leirasa megtalalhato a NetLock Kft. Internet honlapjan a https://www.netlock.net/docs cimen vagy kerheto az ellenorzes@netlock.net e-mail cimen. IMPORTANT! The issuance and the use of this certificate is subject to the NetLock CPS available at https://www.netlock.net/docs or by e-mail at cps@netlock.net.
+    Signature Algorithm: md5WithRSAEncryption
+        48:24:46:f7:ba:56:6f:fa:c8:28:03:40:4e:e5:31:39:6b:26:
+        6b:53:7f:db:df:df:f3:71:3d:26:c0:14:0e:c6:67:7b:23:a8:
+        0c:73:dd:01:bb:c6:ca:6e:37:39:55:d5:c7:8c:56:20:0e:28:
+        0a:0e:d2:2a:a4:b0:49:52:c6:38:07:fe:be:0a:09:8c:d1:98:
+        cf:ca:da:14:31:a1:4f:d2:39:fc:0f:11:2c:43:c3:dd:ab:93:
+        c7:55:3e:47:7c:18:1a:00:dc:f3:7b:d8:f2:7f:52:6c:20:f4:
+        0b:5f:69:52:f4:ee:f8:b2:29:60:eb:e3:49:31:21:0d:d6:b5:
+        10:41:e2:41:09:6c:e2:1a:9a:56:4b:77:02:f6:a0:9b:9a:27:
+        87:e8:55:29:71:c2:90:9f:45:78:1a:e1:15:64:3d:d0:0e:d8:
+        a0:76:9f:ae:c5:d0:2e:ea:d6:0f:56:ec:64:7f:5a:9b:14:58:
+        01:27:7e:13:50:c7:6b:2a:e6:68:3c:bf:5c:a0:0a:1b:e1:0e:
+        7a:e9:e2:80:c3:e9:e9:f6:fd:6c:11:9e:d0:e5:28:27:2b:54:
+        32:42:14:82:75:e6:4a:f0:2b:66:75:63:8c:a2:fb:04:3e:83:
+        0e:9b:36:f0:18:e4:26:20:c3:8c:f0:28:07:ad:3c:17:66:88:
+        b5:fd:b6:88
+SHA1 Fingerprint=AC:ED:5F:65:53:FD:25:CE:01:5F:1F:7A:48:3B:6A:74:9F:61:78:C6
+-----BEGIN CERTIFICATE-----
+MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhV
+MRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMe
+TmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0
+dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFzcyBB
+KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oXDTE5MDIxOTIzMTQ0
+N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhC
+dWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQu
+MRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBL
+b3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSMD7tM9DceqQWC2ObhbHDqeLVu0ThEDaiD
+zl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZz+qMkjvN9wfcZnSX9EUi
+3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC/tmwqcm8
+WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LY
+Oph7tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2Esi
+NCubMvJIH5+hCoR64sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCC
+ApswDgYDVR0PAQH/BAQDAgAGMBIGA1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4
+QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZRUxFTSEgRXplbiB0
+YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRhdGFz
+aSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu
+IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtm
+ZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMg
+ZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVs
+amFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJhc2EgbWVndGFsYWxoYXRv
+IGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBzOi8vd3d3
+Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6
+ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1
+YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3Qg
+dG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRs
+b2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNAbmV0bG9jay5uZXQuMA0G
+CSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5ayZrU3/b39/zcT0mwBQO
+xmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjPytoUMaFP
+0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQ
+QeJBCWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxk
+f1qbFFgBJ34TUMdrKuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK
+8CtmdWOMovsEPoMOmzbwGOQmIMOM8CgHrTwXZoi1/baI
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/b0f3e76e.0 b/libcore/security/src/main/files/cacerts/b0f3e76e.0
new file mode 100644
index 0000000..05ce1ec
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/b0f3e76e.0
@@ -0,0 +1,79 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            02:00:00:00:00:00:d6:78:b7:94:05
+        Signature Algorithm: md5WithRSAEncryption
+        Issuer: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA
+        Validity
+            Not Before: Sep  1 12:00:00 1998 GMT
+            Not After : Jan 28 12:00:00 2014 GMT
+        Subject: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:da:0e:e6:99:8d:ce:a3:e3:4f:8a:7e:fb:f1:8b:
+                    83:25:6b:ea:48:1f:f1:2a:b0:b9:95:11:04:bd:f0:
+                    63:d1:e2:67:66:cf:1c:dd:cf:1b:48:2b:ee:8d:89:
+                    8e:9a:af:29:80:65:ab:e9:c7:2d:12:cb:ab:1c:4c:
+                    70:07:a1:3d:0a:30:cd:15:8d:4f:f8:dd:d4:8c:50:
+                    15:1c:ef:50:ee:c4:2e:f7:fc:e9:52:f2:91:7d:e0:
+                    6d:d5:35:30:8e:5e:43:73:f2:41:e9:d5:6a:e3:b2:
+                    89:3a:56:39:38:6f:06:3c:88:69:5b:2a:4d:c5:a7:
+                    54:b8:6c:89:cc:9b:f9:3c:ca:e5:fd:89:f5:12:3c:
+                    92:78:96:d6:dc:74:6e:93:44:61:d1:8d:c7:46:b2:
+                    75:0e:86:e8:19:8a:d5:6d:6c:d5:78:16:95:a2:e9:
+                    c8:0a:38:eb:f2:24:13:4f:73:54:93:13:85:3a:1b:
+                    bc:1e:34:b5:8b:05:8c:b9:77:8b:b1:db:1f:20:91:
+                    ab:09:53:6e:90:ce:7b:37:74:b9:70:47:91:22:51:
+                    63:16:79:ae:b1:ae:41:26:08:c8:19:2b:d1:46:aa:
+                    48:d6:64:2a:d7:83:34:ff:2c:2a:c1:6c:19:43:4a:
+                    07:85:e7:d3:7c:f6:21:68:ef:ea:f2:52:9f:7f:93:
+                    90:cf
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            X509v3 Subject Key Identifier: 
+                60:7B:66:1A:45:0D:97:CA:89:50:2F:7D:04:CD:34:A8:FF:FC:FD:4B
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: md5WithRSAEncryption
+        ae:aa:9f:fc:b7:d2:cb:1f:5f:39:29:28:18:9e:34:c9:6c:4f:
+        6f:1a:f0:64:a2:70:4a:4f:13:86:9b:60:28:9e:e8:81:49:98:
+        7d:0a:bb:e5:b0:9d:3d:36:db:8f:05:51:ff:09:31:2a:1f:dd:
+        89:77:9e:0f:2e:6c:95:04:ed:86:cb:b4:00:3f:84:02:4d:80:
+        6a:2a:2d:78:0b:ae:6f:2b:a2:83:44:83:1f:cd:50:82:4c:24:
+        af:bd:f7:a5:b4:c8:5a:0f:f4:e7:47:5e:49:8e:37:96:fe:9a:
+        88:05:3a:d9:c0:db:29:87:e6:19:96:47:a7:3a:a6:8c:8b:3c:
+        77:fe:46:63:a7:53:da:21:d1:ac:7e:49:a2:4b:e6:c3:67:59:
+        2f:b3:8a:0e:bb:2c:bd:a9:aa:42:7c:35:c1:d8:7f:d5:a7:31:
+        3a:4e:63:43:39:af:08:b0:61:34:8c:d3:98:a9:43:34:f6:0f:
+        87:29:3b:9d:c2:56:58:98:77:c3:f7:1b:ac:f6:9d:f8:3e:aa:
+        a7:54:45:f0:f5:f9:d5:31:65:fe:6b:58:9c:71:b3:1e:d7:52:
+        ea:32:17:fc:40:60:1d:c9:79:24:b2:f6:6c:fd:a8:66:0e:82:
+        dd:98:cb:da:c2:44:4f:2e:a0:7b:f2:f7:6b:2c:76:11:84:46:
+        8a:78:a3:e3
+SHA1 Fingerprint=2F:17:3F:7D:E9:96:67:AF:A5:7A:F8:0A:A2:D1:B1:2F:AC:83:03:38
+-----BEGIN CERTIFICATE-----
+MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
+MDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
+aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
+jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
+xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
+1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
+snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
+U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
+9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQU
+YHtmGkUNl8qJUC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B
+AQQFAAOCAQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq7
+5bCdPTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q
+gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT2iHR
+rH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlDNPYPhyk7
+ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBgHcl5JLL2bP2o
+Zg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w==
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/bcdd5959.0 b/libcore/security/src/main/files/cacerts/bcdd5959.0
new file mode 100644
index 0000000..b55d346
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/bcdd5959.0
@@ -0,0 +1,52 @@
+Certificate:
+    Data:
+        Version: 1 (0x0)
+        Serial Number: 1 (0x1)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: L=ValiCert Validation Network, O=ValiCert, Inc., OU=ValiCert Class 2 Policy Validation Authority, CN=http://www.valicert.com//emailAddress=info@valicert.com
+        Validity
+            Not Before: Jun 26 00:19:54 1999 GMT
+            Not After : Jun 26 00:19:54 2019 GMT
+        Subject: L=ValiCert Validation Network, O=ValiCert, Inc., OU=ValiCert Class 2 Policy Validation Authority, CN=http://www.valicert.com//emailAddress=info@valicert.com
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:ce:3a:71:ca:e5:ab:c8:59:92:55:d7:ab:d8:74:
+                    0e:f9:ee:d9:f6:55:47:59:65:47:0e:05:55:dc:eb:
+                    98:36:3c:5c:53:5d:d3:30:cf:38:ec:bd:41:89:ed:
+                    25:42:09:24:6b:0a:5e:b3:7c:dd:52:2d:4c:e6:d4:
+                    d6:7d:5a:59:a9:65:d4:49:13:2d:24:4d:1c:50:6f:
+                    b5:c1:85:54:3b:fe:71:e4:d3:5c:42:f9:80:e0:91:
+                    1a:0a:5b:39:36:67:f3:3f:55:7c:1b:3f:b4:5f:64:
+                    73:34:e3:b4:12:bf:87:64:f8:da:12:ff:37:27:c1:
+                    b3:43:bb:ef:7b:6e:2e:69:f7
+                Exponent: 65537 (0x10001)
+    Signature Algorithm: sha1WithRSAEncryption
+        3b:7f:50:6f:6f:50:94:99:49:62:38:38:1f:4b:f8:a5:c8:3e:
+        a7:82:81:f6:2b:c7:e8:c5:ce:e8:3a:10:82:cb:18:00:8e:4d:
+        bd:a8:58:7f:a1:79:00:b5:bb:e9:8d:af:41:d9:0f:34:ee:21:
+        81:19:a0:32:49:28:f4:c4:8e:56:d5:52:33:fd:50:d5:7e:99:
+        6c:03:e4:c9:4c:fc:cb:6c:ab:66:b3:4a:21:8c:e5:b5:0c:32:
+        3e:10:b2:cc:6c:a1:dc:9a:98:4c:02:5b:f3:ce:b9:9e:a5:72:
+        0e:4a:b7:3f:3c:e6:16:68:f8:be:ed:74:4c:bc:5b:d5:62:1f:
+        43:dd
+SHA1 Fingerprint=31:7A:2A:D0:7F:2B:33:5E:F5:A1:C3:4E:4B:57:E8:B7:D8:F1:FC:A6
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy
+NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY
+dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9
+WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS
+v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v
+UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu
+IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC
+W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/bda4cc84.0 b/libcore/security/src/main/files/cacerts/bda4cc84.0
new file mode 100644
index 0000000..4795994
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/bda4cc84.0
@@ -0,0 +1,82 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=US, O=America Online Inc., CN=America Online Root Certification Authority 1
+        Validity
+            Not Before: May 28 06:00:00 2002 GMT
+            Not After : Nov 19 20:43:00 2037 GMT
+        Subject: C=US, O=America Online Inc., CN=America Online Root Certification Authority 1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:a8:2f:e8:a4:69:06:03:47:c3:e9:2a:98:ff:19:
+                    a2:70:9a:c6:50:b2:7e:a5:df:68:4d:1b:7c:0f:b6:
+                    97:68:7d:2d:a6:8b:97:e9:64:86:c9:a3:ef:a0:86:
+                    bf:60:65:9c:4b:54:88:c2:48:c5:4a:39:bf:14:e3:
+                    59:55:e5:19:b4:74:c8:b4:05:39:5c:16:a5:e2:95:
+                    05:e0:12:ae:59:8b:a2:33:68:58:1c:a6:d4:15:b7:
+                    d8:9f:d7:dc:71:ab:7e:9a:bf:9b:8e:33:0f:22:fd:
+                    1f:2e:e7:07:36:ef:62:39:c5:dd:cb:ba:25:14:23:
+                    de:0c:c6:3d:3c:ce:82:08:e6:66:3e:da:51:3b:16:
+                    3a:a3:05:7f:a0:dc:87:d5:9c:fc:72:a9:a0:7d:78:
+                    e4:b7:31:55:1e:65:bb:d4:61:b0:21:60:ed:10:32:
+                    72:c5:92:25:1e:f8:90:4a:18:78:47:df:7e:30:37:
+                    3e:50:1b:db:1c:d3:6b:9a:86:53:07:b0:ef:ac:06:
+                    78:f8:84:99:fe:21:8d:4c:80:b6:0c:82:f6:66:70:
+                    79:1a:d3:4f:a3:cf:f1:cf:46:b0:4b:0f:3e:dd:88:
+                    62:b8:8c:a9:09:28:3b:7a:c7:97:e1:1e:e5:f4:9f:
+                    c0:c0:ae:24:a0:c8:a1:d9:0f:d6:7b:26:82:69:32:
+                    3d:a7
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            X509v3 Subject Key Identifier: 
+                00:AD:D9:A3:F6:79:F6:6E:74:A9:7F:33:3D:81:17:D7:4C:CF:33:DE
+            X509v3 Authority Key Identifier: 
+                keyid:00:AD:D9:A3:F6:79:F6:6E:74:A9:7F:33:3D:81:17:D7:4C:CF:33:DE
+
+            X509v3 Key Usage: critical
+                Digital Signature, Certificate Sign, CRL Sign
+    Signature Algorithm: sha1WithRSAEncryption
+        7c:8a:d1:1f:18:37:82:e0:b8:b0:a3:ed:56:95:c8:62:61:9c:
+        05:a2:cd:c2:62:26:61:cd:10:16:d7:cc:b4:65:34:d0:11:8a:
+        ad:a8:a9:05:66:ef:74:f3:6d:5f:9d:99:af:f6:8b:fb:eb:52:
+        b2:05:98:a2:6f:2a:c5:54:bd:25:bd:5f:ae:c8:86:ea:46:2c:
+        c1:b3:bd:c1:e9:49:70:18:16:97:08:13:8c:20:e0:1b:2e:3a:
+        47:cb:1e:e4:00:30:95:5b:f4:45:a3:c0:1a:b0:01:4e:ab:bd:
+        c0:23:6e:63:3f:80:4a:c5:07:ed:dc:e2:6f:c7:c1:62:f1:e3:
+        72:d6:04:c8:74:67:0b:fa:88:ab:a1:01:c8:6f:f0:14:af:d2:
+        99:cd:51:93:7e:ed:2e:38:c7:bd:ce:46:50:3d:72:e3:79:25:
+        9d:9b:88:2b:10:20:dd:a5:b8:32:9f:8d:e0:29:df:21:74:86:
+        82:db:2f:82:30:c6:c7:35:86:b3:f9:96:5f:46:db:0c:45:fd:
+        f3:50:c3:6f:c6:c3:48:ad:46:a6:e1:27:47:0a:1d:0e:9b:b6:
+        c2:77:7f:63:f2:e0:7d:1a:be:fc:e0:df:d7:c7:a7:6c:b0:f9:
+        ae:ba:3c:fd:74:b4:11:e8:58:0d:80:bc:d3:a8:80:3a:99:ed:
+        75:cc:46:7b
+SHA1 Fingerprint=39:21:C1:15:C1:5D:0E:CA:5C:CB:5B:C4:F0:7D:21:D8:05:0B:56:6A
+-----BEGIN CERTIFICATE-----
+MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP
+bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2
+MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft
+ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lk
+hsmj76CGv2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym
+1BW32J/X3HGrfpq/m44zDyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsW
+OqMFf6Dch9Wc/HKpoH145LcxVR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb
+2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQko
+O3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAU
+AK3Zo/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
+BQUAA4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF
+Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAb
+LjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTIdGcL+oir
+oQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43gKd8hdIaC2y+C
+MMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds
+sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/c33a80d4.0 b/libcore/security/src/main/files/cacerts/c33a80d4.0
new file mode 100644
index 0000000..5262d83
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/c33a80d4.0
@@ -0,0 +1,56 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+        Signature Algorithm: md5WithRSAEncryption
+        Issuer: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Premium Server CA/emailAddress=premium-server@thawte.com
+        Validity
+            Not Before: Aug  1 00:00:00 1996 GMT
+            Not After : Dec 31 23:59:59 2020 GMT
+        Subject: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Premium Server CA/emailAddress=premium-server@thawte.com
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:d2:36:36:6a:8b:d7:c2:5b:9e:da:81:41:62:8f:
+                    38:ee:49:04:55:d6:d0:ef:1c:1b:95:16:47:ef:18:
+                    48:35:3a:52:f4:2b:6a:06:8f:3b:2f:ea:56:e3:af:
+                    86:8d:9e:17:f7:9e:b4:65:75:02:4d:ef:cb:09:a2:
+                    21:51:d8:9b:d0:67:d0:ba:0d:92:06:14:73:d4:93:
+                    cb:97:2a:00:9c:5c:4e:0c:bc:fa:15:52:fc:f2:44:
+                    6e:da:11:4a:6e:08:9f:2f:2d:e3:f9:aa:3a:86:73:
+                    b6:46:53:58:c8:89:05:bd:83:11:b8:73:3f:aa:07:
+                    8d:f4:42:4d:e7:40:9d:1c:37
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: md5WithRSAEncryption
+        26:48:2c:16:c2:58:fa:e8:16:74:0c:aa:aa:5f:54:3f:f2:d7:
+        c9:78:60:5e:5e:6e:37:63:22:77:36:7e:b2:17:c4:34:b9:f5:
+        08:85:fc:c9:01:38:ff:4d:be:f2:16:42:43:e7:bb:5a:46:fb:
+        c1:c6:11:1f:f1:4a:b0:28:46:c9:c3:c4:42:7d:bc:fa:ab:59:
+        6e:d5:b7:51:88:11:e3:a4:85:19:6b:82:4c:a4:0c:12:ad:e9:
+        a4:ae:3f:f1:c3:49:65:9a:8c:c5:c8:3e:25:b7:94:99:bb:92:
+        32:71:07:f0:86:5e:ed:50:27:a6:0d:a6:23:f9:bb:cb:a6:07:
+        14:42
+SHA1 Fingerprint=62:7F:8D:78:27:65:63:99:D2:7D:7F:90:44:C9:FE:B3:F3:3E:FA:9A
+-----BEGIN CERTIFICATE-----
+MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
+VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy
+dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t
+MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB
+MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG
+A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp
+b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl
+cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv
+bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE
+VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ
+ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR
+uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
+9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI
+hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM
+pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg==
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/cb796bc1.0 b/libcore/security/src/main/files/cacerts/cb796bc1.0
new file mode 100644
index 0000000..dd38d87
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/cb796bc1.0
@@ -0,0 +1,90 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 0 (0x0)
+        Signature Algorithm: md5WithRSAEncryption
+        Issuer: C=IL, ST=Israel, L=Eilat, O=StartCom Ltd., OU=CA Authority Dep., CN=Free SSL Certification Authority/emailAddress=admin@startcom.org
+        Validity
+            Not Before: Mar 17 17:37:48 2005 GMT
+            Not After : Mar 10 17:37:48 2035 GMT
+        Subject: C=IL, ST=Israel, L=Eilat, O=StartCom Ltd., OU=CA Authority Dep., CN=Free SSL Certification Authority/emailAddress=admin@startcom.org
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:ed:84:60:00:23:9e:c8:4a:51:29:27:de:3a:a1:
+                    39:b5:69:ab:09:b2:2f:34:fd:61:dc:3d:d3:b0:cf:
+                    b1:d7:c2:c4:c2:b1:e4:96:56:c4:be:aa:14:0e:e7:
+                    cc:3a:50:c8:3a:62:9d:c3:a3:ac:59:7b:8e:ee:55:
+                    1a:1c:47:be:a3:97:39:b3:b5:ef:23:2c:08:e8:d8:
+                    af:73:2f:b9:c9:83:e8:ed:00:0f:c8:75:a5:2f:34:
+                    4c:18:e8:76:88:23:49:8a:db:b6:ed:68:da:c3:b5:
+                    62:29:4c:a5:4b:b7:98:b4:09:14:10:a0:f8:fe:62:
+                    76:22:15:0b:a4:d6:08:2f:35
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            X509v3 Key Usage: 
+                Digital Signature, Non Repudiation, Key Encipherment, Certificate Sign, CRL Sign
+            X509v3 Subject Key Identifier: 
+                1C:89:C3:96:CC:BD:FE:32:D5:0D:8C:81:31:B6:98:9D:8D:28:64:8D
+            X509v3 Authority Key Identifier: 
+                keyid:1C:89:C3:96:CC:BD:FE:32:D5:0D:8C:81:31:B6:98:9D:8D:28:64:8D
+                DirName:/C=IL/ST=Israel/L=Eilat/O=StartCom Ltd./OU=CA Authority Dep./CN=Free SSL Certification Authority/emailAddress=admin@startcom.org
+                serial:00
+
+            X509v3 Subject Alternative Name: 
+                email:admin@startcom.org
+            X509v3 Issuer Alternative Name: 
+                email:admin@startcom.org
+            Netscape Cert Type: 
+                SSL CA, S/MIME CA, Object Signing CA
+            Netscape Comment: 
+                Free SSL Certification Authority
+            Netscape CA Revocation Url: 
+                http://cert.startcom.org/ca-crl.crl
+            Netscape Base Url: 
+                http://cert.startcom.org/
+            Netscape CA Policy Url: 
+                http://cert.startcom.org/index.php?app=111
+    Signature Algorithm: md5WithRSAEncryption
+        6c:71:25:e1:9e:34:91:21:ef:db:6c:bd:01:08:56:8f:88:d8:
+        41:3a:53:f5:72:df:27:57:4b:76:84:f7:68:a4:fe:eb:3f:09:
+        7e:28:b8:57:ea:1f:c1:aa:e2:ff:96:9f:49:99:e6:b2:95:73:
+        96:c6:48:c7:5e:8d:07:72:56:f8:83:8f:9f:77:af:29:d3:45:
+        0e:a4:ee:b0:36:74:2d:f0:cd:98:23:7b:37:4b:da:fe:51:98:
+        c4:1e:34:3c:88:fd:99:3b:50:a7:c1:8b:33:c7:c2:52:16:12:
+        95:53:65:22:ef:ba:8b:ce:62:db:70:23:b1:80:df:1a:20:38:
+        e7:7e
+SHA1 Fingerprint=95:E6:AD:F8:D7:71:46:02:4D:D5:6A:21:B2:E7:3F:CD:F2:3B:35:FF
+-----BEGIN CERTIFICATE-----
+MIIFFjCCBH+gAwIBAgIBADANBgkqhkiG9w0BAQQFADCBsDELMAkGA1UEBhMCSUwx
+DzANBgNVBAgTBklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoTDVN0YXJ0
+Q29tIEx0ZC4xGjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkwJwYDVQQDEyBG
+cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS
+YWRtaW5Ac3RhcnRjb20ub3JnMB4XDTA1MDMxNzE3Mzc0OFoXDTM1MDMxMDE3Mzc0
+OFowgbAxCzAJBgNVBAYTAklMMQ8wDQYDVQQIEwZJc3JhZWwxDjAMBgNVBAcTBUVp
+bGF0MRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMRowGAYDVQQLExFDQSBBdXRob3Jp
+dHkgRGVwLjEpMCcGA1UEAxMgRnJlZSBTU0wgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkxITAfBgkqhkiG9w0BCQEWEmFkbWluQHN0YXJ0Y29tLm9yZzCBnzANBgkqhkiG
+9w0BAQEFAAOBjQAwgYkCgYEA7YRgACOeyEpRKSfeOqE5tWmrCbIvNP1h3D3TsM+x
+18LEwrHkllbEvqoUDufMOlDIOmKdw6OsWXuO7lUaHEe+o5c5s7XvIywI6Nivcy+5
+yYPo7QAPyHWlLzRMGOh2iCNJitu27Wjaw7ViKUylS7eYtAkUEKD4/mJ2IhULpNYI
+LzUCAwEAAaOCAjwwggI4MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgHmMB0G
+A1UdDgQWBBQcicOWzL3+MtUNjIExtpidjShkjTCB3QYDVR0jBIHVMIHSgBQcicOW
+zL3+MtUNjIExtpidjShkjaGBtqSBszCBsDELMAkGA1UEBhMCSUwxDzANBgNVBAgT
+BklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4x
+GjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkwJwYDVQQDEyBGcmVlIFNTTCBD
+ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSYWRtaW5Ac3Rh
+cnRjb20ub3JnggEAMB0GA1UdEQQWMBSBEmFkbWluQHN0YXJ0Y29tLm9yZzAdBgNV
+HRIEFjAUgRJhZG1pbkBzdGFydGNvbS5vcmcwEQYJYIZIAYb4QgEBBAQDAgAHMC8G
+CWCGSAGG+EIBDQQiFiBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAy
+BglghkgBhvhCAQQEJRYjaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL2NhLWNybC5j
+cmwwKAYJYIZIAYb4QgECBBsWGWh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy8wOQYJ
+YIZIAYb4QgEIBCwWKmh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9pbmRleC5waHA/
+YXBwPTExMTANBgkqhkiG9w0BAQQFAAOBgQBscSXhnjSRIe/bbL0BCFaPiNhBOlP1
+ct8nV0t2hPdopP7rPwl+KLhX6h/BquL/lp9JmeaylXOWxkjHXo0Hclb4g4+fd68p
+00UOpO6wNnQt8M2YI3s3S9r+UZjEHjQ8iP2ZO1CnwYszx8JSFhKVU2Ui77qLzmLb
+cCOxgN8aIDjnfg==
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/cdaebb72.0 b/libcore/security/src/main/files/cacerts/cdaebb72.0
new file mode 100644
index 0000000..2281720
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/cdaebb72.0
@@ -0,0 +1,83 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 10000010 (0x98968a)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=NL, O=Staat der Nederlanden, CN=Staat der Nederlanden Root CA
+        Validity
+            Not Before: Dec 17 09:23:49 2002 GMT
+            Not After : Dec 16 09:15:38 2015 GMT
+        Subject: C=NL, O=Staat der Nederlanden, CN=Staat der Nederlanden Root CA
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:98:d2:b5:51:11:7a:81:a6:14:98:71:6d:be:cc:
+                    e7:13:1b:d6:27:0e:7a:b3:6a:18:1c:b6:61:5a:d5:
+                    61:09:bf:de:90:13:c7:67:ee:dd:f3:da:c5:0c:12:
+                    9e:35:55:3e:2c:27:88:40:6b:f7:dc:dd:22:61:f5:
+                    c2:c7:0e:f5:f6:d5:76:53:4d:8f:8c:bc:18:76:37:
+                    85:9d:e8:ca:49:c7:d2:4f:98:13:09:a2:3e:22:88:
+                    9c:7f:d6:f2:10:65:b4:ee:5f:18:d5:17:e3:f8:c5:
+                    fd:e2:9d:a2:ef:53:0e:85:77:a2:0f:e1:30:47:ee:
+                    00:e7:33:7d:44:67:1a:0b:51:e8:8b:a0:9e:50:98:
+                    68:34:52:1f:2e:6d:01:f2:60:45:f2:31:eb:a9:31:
+                    68:29:bb:7a:41:9e:c6:19:7f:94:b4:51:39:03:7f:
+                    b2:de:a7:32:9b:b4:47:8e:6f:b4:4a:ae:e5:af:b1:
+                    dc:b0:1b:61:bc:99:72:de:e4:89:b7:7a:26:5d:da:
+                    33:49:5b:52:9c:0e:f5:8a:ad:c3:b8:3d:e8:06:6a:
+                    c2:d5:2a:0b:6c:7b:84:bd:56:05:cb:86:65:92:ec:
+                    44:2b:b0:8e:b9:dc:70:0b:46:da:ad:bc:63:88:39:
+                    fa:db:6a:fe:23:fa:bc:e4:48:f4:67:2b:6a:11:10:
+                    21:49
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:TRUE
+            X509v3 Certificate Policies: 
+                Policy: X509v3 Any Policy
+                  CPS: http://www.pkioverheid.nl/policies/root-policy
+
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            X509v3 Subject Key Identifier: 
+                A8:7D:EB:BC:63:A4:74:13:74:00:EC:96:E0:D3:34:C1:2C:BF:6C:F8
+    Signature Algorithm: sha1WithRSAEncryption
+        05:84:87:55:74:36:61:c1:bb:d1:d4:c6:15:a8:13:b4:9f:a4:
+        fe:bb:ee:15:b4:2f:06:0c:29:f2:a8:92:a4:61:0d:fc:ab:5c:
+        08:5b:51:13:2b:4d:c2:2a:61:c8:f8:09:58:fc:2d:02:b2:39:
+        7d:99:66:81:bf:6e:5c:95:45:20:6c:e6:79:a7:d1:d8:1c:29:
+        fc:c2:20:27:51:c8:f1:7c:5d:34:67:69:85:11:30:c6:00:d2:
+        d7:f3:d3:7c:b6:f0:31:57:28:12:82:73:e9:33:2f:a6:55:b4:
+        0b:91:94:47:9c:fa:bb:7a:42:32:e8:ae:7e:2d:c8:bc:ac:14:
+        bf:d9:0f:d9:5b:fc:c1:f9:7a:95:e1:7d:7e:96:fc:71:b0:c2:
+        4c:c8:df:45:34:c9:ce:0d:f2:9c:64:08:d0:3b:c3:29:c5:b2:
+        ed:90:04:c1:b1:29:91:c5:30:6f:c1:a9:72:33:cc:fe:5d:16:
+        17:2c:11:69:e7:7e:fe:c5:83:08:df:bc:dc:22:3a:2e:20:69:
+        23:39:56:60:67:90:8b:2e:76:39:fb:11:88:97:f6:7c:bd:4b:
+        b8:20:16:67:05:8d:e2:3b:c1:72:3f:94:95:37:c7:5d:b9:9e:
+        d8:93:a1:17:8f:ff:0c:66:15:c1:24:7c:32:7c:03:1d:3b:a1:
+        58:45:32:93
+SHA1 Fingerprint=10:1D:FA:3F:D5:0B:CB:BB:9B:B5:60:0C:19:55:A4:1A:F4:73:3A:04
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJO
+TDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFh
+dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEy
+MTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVk
+ZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxhbmRlbiBSb290IENB
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFtvszn
+ExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw71
+9tV2U02PjLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MO
+hXeiD+EwR+4A5zN9RGcaC1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+U
+tFE5A3+y3qcym7RHjm+0Sq7lr7HcsBthvJly3uSJt3omXdozSVtSnA71iq3DuD3o
+BmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn622r+I/q85Ej0ZytqERAh
+SQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRVHSAAMDww
+OgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMv
+cm9vdC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA
+7Jbg0zTBLL9s+DANBgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k
+/rvuFbQvBgwp8qiSpGEN/KtcCFtREytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzm
+eafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbwMVcoEoJz6TMvplW0C5GUR5z6
+u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3ynGQI0DvDKcWy
+7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR
+iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw==
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/d537fba6.0 b/libcore/security/src/main/files/cacerts/d537fba6.0
new file mode 100644
index 0000000..9a5375c
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/d537fba6.0
@@ -0,0 +1,94 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 986490188 (0x3acca54c)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=DK, O=TDC Internet, OU=TDC Internet Root CA
+        Validity
+            Not Before: Apr  5 16:33:17 2001 GMT
+            Not After : Apr  5 17:03:17 2021 GMT
+        Subject: C=DK, O=TDC Internet, OU=TDC Internet Root CA
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:c4:b8:40:bc:91:d5:63:1f:d7:99:a0:8b:0c:40:
+                    1e:74:b7:48:9d:46:8c:02:b2:e0:24:5f:f0:19:13:
+                    a7:37:83:6b:5d:c7:8e:f9:84:30:ce:1a:3b:fa:fb:
+                    ce:8b:6d:23:c6:c3:6e:66:9f:89:a5:df:e0:42:50:
+                    67:fa:1f:6c:1e:f4:d0:05:d6:bf:ca:d6:4e:e4:68:
+                    60:6c:46:aa:1c:5d:63:e1:07:86:0e:65:00:a7:2e:
+                    a6:71:c6:bc:b9:81:a8:3a:7d:1a:d2:f9:d1:ac:4b:
+                    cb:ce:75:af:dc:7b:fa:81:73:d4:fc:ba:bd:41:88:
+                    d4:74:b3:f9:5e:38:3a:3c:43:a8:d2:95:4e:77:6d:
+                    13:0c:9d:8f:78:01:b7:5a:20:1f:03:37:35:e2:2c:
+                    db:4b:2b:2c:78:b9:49:db:c4:d0:c7:9c:9c:e4:8a:
+                    20:09:21:16:56:66:ff:05:ec:5b:e3:f0:cf:ab:24:
+                    24:5e:c3:7f:70:7a:12:c4:d2:b5:10:a0:b6:21:e1:
+                    8d:78:69:55:44:69:f5:ca:96:1c:34:85:17:25:77:
+                    e2:f6:2f:27:98:78:fd:79:06:3a:a2:d6:5a:43:c1:
+                    ff:ec:04:3b:ee:13:ef:d3:58:5a:ff:92:eb:ec:ae:
+                    da:f2:37:03:47:41:b6:97:c9:2d:0a:41:22:bb:bb:
+                    e6:a7
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            Netscape Cert Type: 
+                SSL CA, S/MIME CA, Object Signing CA
+            X509v3 CRL Distribution Points: 
+                DirName:/C=DK/O=TDC Internet/OU=TDC Internet Root CA/CN=CRL1
+
+            X509v3 Private Key Usage Period: 
+                Not Before: Apr  5 16:33:17 2001 GMT, Not After: Apr  5 17:03:17 2021 GMT
+            X509v3 Key Usage: 
+                Certificate Sign, CRL Sign
+            X509v3 Authority Key Identifier: 
+                keyid:6C:64:01:C7:FD:85:6D:AC:C8:DA:9E:50:08:85:08:B5:3C:56:A8:50
+
+            X509v3 Subject Key Identifier: 
+                6C:64:01:C7:FD:85:6D:AC:C8:DA:9E:50:08:85:08:B5:3C:56:A8:50
+            X509v3 Basic Constraints: 
+                CA:TRUE
+            1.2.840.113533.7.65.0: 
+                0...V5.0:4.0....
+    Signature Algorithm: sha1WithRSAEncryption
+        4e:43:cc:d1:dd:1d:10:1b:06:7f:b7:a4:fa:d3:d9:4d:fb:23:
+        9f:23:54:5b:e6:8b:2f:04:28:8b:b5:27:6d:89:a1:ec:98:69:
+        dc:e7:8d:26:83:05:79:74:ec:b4:b9:a3:97:c1:35:00:fd:15:
+        da:39:81:3a:95:31:90:de:97:e9:86:a8:99:77:0c:e5:5a:a0:
+        84:ff:12:16:ac:6e:b8:8d:c3:7b:92:c2:ac:2e:d0:7d:28:ec:
+        b6:f3:60:38:69:6f:3e:d8:04:55:3e:9e:cc:55:d2:ba:fe:bb:
+        47:04:d7:0a:d9:16:0a:34:29:f5:58:13:d5:4f:cf:8f:56:4b:
+        b3:1e:ee:d3:98:79:da:08:1e:0c:6f:b8:f8:16:27:ef:c2:6f:
+        3d:f6:a3:4b:3e:0e:e4:6d:6c:db:3b:41:12:9b:bd:0d:47:23:
+        7f:3c:4a:d0:af:c0:af:f6:ef:1b:b5:15:c4:eb:83:c4:09:5f:
+        74:8b:d9:11:fb:c2:56:b1:3c:f8:70:ca:34:8d:43:40:13:8c:
+        fd:99:03:54:79:c6:2e:ea:86:a1:f6:3a:d4:09:bc:f4:bc:66:
+        cc:3d:58:d0:57:49:0a:ee:25:e2:41:ee:13:f9:9b:38:34:d1:
+        00:f5:7e:e7:94:1d:fc:69:03:62:b8:99:05:05:3d:6b:78:12:
+        bd:b0:6f:65
+SHA1 Fingerprint=21:FC:BD:8E:7F:6C:AF:05:1B:D1:B3:43:EC:A8:E7:61:47:F2:0F:8A
+-----BEGIN CERTIFICATE-----
+MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJE
+SzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQg
+Um9vdCBDQTAeFw0wMTA0MDUxNjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNV
+BAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJuZXQxHTAbBgNVBAsTFFREQyBJbnRl
+cm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLhA
+vJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20jxsNu
+Zp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a
+0vnRrEvLznWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc1
+4izbSysseLlJ28TQx5yc5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGN
+eGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcD
+R0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZIAYb4QgEBBAQDAgAHMGUG
+A1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMMVERDIElu
+dGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxME
+Q1JMMTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3
+WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAw
+HQYDVR0OBBYEFGxkAcf9hW2syNqeUAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJ
+KoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQBO
+Q8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540mgwV5dOy0uaOX
+wTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+
+2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm89
+9qNLPg7kbWzbO0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0
+jUNAE4z9mQNUecYu6oah9jrUCbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38
+aQNiuJkFBT1reBK9sG9l
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/d777342d.0 b/libcore/security/src/main/files/cacerts/d777342d.0
new file mode 100644
index 0000000..667cac3
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/d777342d.0
@@ -0,0 +1,23 @@
+
+subject=/C=JP/O=Japan Certification Services, Inc./CN=SecureSign RootCA1
+issuer=/C=JP/O=Japan Certification Services, Inc./CN=SecureSign RootCA1
+-----BEGIN CERTIFICATE-----
+MIIDKTCCAhECCF9gWF8AAAAAMA0GCSqGSIb3DQEBBQUAMFcxCzAJBgNVBAYTAkpQ
+MSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRsw
+GQYDVQQDExJTZWN1cmVTaWduIFJvb3RDQTEwHhcNOTkwOTE1MTUwMDAxWhcNMjAw
+OTE1MTQ1OTU5WjBXMQswCQYDVQQGEwJKUDErMCkGA1UEChMiSmFwYW4gQ2VydGlm
+aWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEbMBkGA1UEAxMSU2VjdXJlU2lnbiBSb290
+Q0ExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlJAMS3EpHNr2aHl6
+pLrn0syNr+hHkJkfxirql2PoH84XV8Yas6jHfIftNTWAurpubb4X/swtG2zvigBJ
+FuHuBl5KB12rPdFQuJFG1NTaFdiUXA7K19q/oPdJPMi7zuomgQoULZwNN0VrQcpX
+izjwJh8x/M80jo93wT/jq1Q8J7TOMkxVE2L8/joWJc8ba6Ijt+DqAmm79yJxbXwL
+GZOhl5zjkWkfaOQvfRBtj2euwRCisF5jSpf35niprSa7VMnftO7FntMl3RNoU/mP
+6Ozl3oHWeD7uUEC0ATysFcGCOy5/8VIni3Lg59v5iynDw0orM4mrXCoH/HwjHitP
+CCL+wQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQBV7W97k+VFMU5o1VWBoggfbN0J
+xXgacFfI3wiBrmZ3xnUP5O9JiwNcbP8ckKRystMWErIG+EaGrr+nFduFTfrCLU2z
+tbBD73x+B9tfs1dGUXYHhkT9B+rxy0tFTWanMybE+UOqjRKz1I1otvcCebQtWtcD
+mAQsaZmv9GY7ZKyywCvIaVSeTE5IGI3OV7U7UeUb1/o5YNtWRRO+52bVI/Z8SACw
+TO80jSKssi7RTDjN+lgDBu46c4cKBTrK5K/Uwe4chX8lFs8nAR+EincI0NNG6CDs
+n6SM8bzNxBI2gB7HCSiv6Ai+wNOyPtcuZz2jzrs0+uKFzazOVR1FW3iF04V6
+-----END CERTIFICATE-----
+
diff --git a/libcore/security/src/main/files/cacerts/d8274e24.0 b/libcore/security/src/main/files/cacerts/d8274e24.0
new file mode 100644
index 0000000..ad94cba
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/d8274e24.0
@@ -0,0 +1,87 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            44:be:0c:8b:50:00:24:b4:11:d3:36:30:4b:c0:33:77
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=US, ST=UT, L=Salt Lake City, O=The USERTRUST Network, OU=http://www.usertrust.com, CN=UTN-USERFirst-Network Applications
+        Validity
+            Not Before: Jul  9 18:48:39 1999 GMT
+            Not After : Jul  9 18:57:49 2019 GMT
+        Subject: C=US, ST=UT, L=Salt Lake City, O=The USERTRUST Network, OU=http://www.usertrust.com, CN=UTN-USERFirst-Network Applications
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:b3:fb:91:a1:e4:36:55:85:ac:06:34:5b:a0:9a:
+                    58:b2:f8:b5:0f:05:77:83:ae:32:b1:76:92:68:ec:
+                    23:4a:c9:76:3f:e3:9c:b6:37:79:03:b9:ab:69:8d:
+                    07:25:b6:19:67:e4:b0:1b:18:73:61:4a:e8:7e:cd:
+                    d3:2f:64:e3:a6:7c:0c:fa:17:80:a3:0d:47:89:4f:
+                    51:71:2f:ee:fc:3f:f9:b8:16:80:87:89:93:25:20:
+                    9a:43:82:69:24:76:28:59:35:a1:1d:c0:7f:83:06:
+                    64:16:20:2c:d3:49:a4:85:b4:c0:61:7f:51:08:f8:
+                    68:15:91:80:cb:a5:d5:ee:3b:3a:f4:84:04:5e:60:
+                    59:a7:8c:34:72:ee:b8:78:c5:d1:3b:12:4a:6f:7e:
+                    65:27:b9:a4:55:c5:b9:6f:43:a4:c5:1d:2c:99:c0:
+                    52:a4:78:4c:15:b3:40:98:08:6b:43:c6:01:b0:7a:
+                    7b:f5:6b:1c:22:3f:cb:ef:ff:a8:d0:3a:4b:76:15:
+                    9e:d2:d1:c6:2e:e3:db:57:1b:32:a2:b8:6f:e8:86:
+                    a6:3f:70:ab:e5:70:92:ab:44:1e:40:50:fb:9c:a3:
+                    62:e4:6c:6e:a0:c8:de:e2:80:42:fa:e9:2f:e8:ce:
+                    32:04:8f:7c:8d:b7:1c:a3:35:3c:15:dd:9e:c3:ae:
+                    97:a5
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Key Usage: 
+                Digital Signature, Non Repudiation, Certificate Sign, CRL Sign
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            X509v3 Subject Key Identifier: 
+                FA:86:C9:DB:E0:BA:E9:78:F5:4B:A8:D6:15:DF:F0:D3:E1:6A:14:3C
+            X509v3 CRL Distribution Points: 
+                URI:http://crl.usertrust.com/UTN-USERFirst-NetworkApplications.crl
+
+    Signature Algorithm: sha1WithRSAEncryption
+        a4:f3:25:cc:d1:d4:91:83:22:d0:cc:32:ab:9b:96:4e:34:91:
+        54:20:25:34:61:5f:2a:02:15:e1:8b:aa:ff:7d:64:51:cf:0a:
+        ff:bc:7d:d8:21:6a:78:cb:2f:51:6f:f8:42:1d:33:bd:eb:b5:
+        7b:94:c3:c3:a9:a0:2d:df:d1:29:1f:1d:fe:8f:3f:bb:a8:45:
+        2a:7f:d1:6e:55:24:e2:bb:02:fb:31:3f:be:e8:bc:ec:40:2b:
+        f8:01:d4:56:38:e4:ca:44:82:b5:61:20:21:67:65:f6:f0:0b:
+        e7:34:f8:a5:c2:9c:a3:5c:40:1f:85:93:95:06:de:4f:d4:27:
+        a9:b6:a5:fc:16:cd:73:31:3f:b8:65:27:cf:d4:53:1a:f0:ac:
+        6e:9f:4f:05:0c:03:81:a7:84:29:c4:5a:bd:64:57:72:ad:3b:
+        cf:37:18:a6:98:c6:ad:06:b4:dc:08:a3:04:d5:29:a4:96:9a:
+        12:67:4a:8c:60:45:9d:f1:23:9a:b0:00:9c:68:b5:98:50:d3:
+        ef:8e:2e:92:65:b1:48:3e:21:be:15:30:2a:0d:b5:0c:a3:6b:
+        3f:ae:7f:57:f5:1f:96:7c:df:6f:dd:82:30:2c:65:1b:40:4a:
+        cd:68:b9:72:ec:71:76:ec:54:8e:1f:85:0c:01:6a:fa:a6:38:
+        ac:1f:c4:84
+SHA1 Fingerprint=5D:98:9C:DB:15:96:11:36:51:65:64:1B:56:0F:DB:EA:2A:C2:3E:F1
+-----BEGIN CERTIFICATE-----
+MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCB
+ozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3Qt
+TmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5WhcNMTkwNzA5MTg1
+NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0
+IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYD
+VQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VS
+Rmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQCz+5Gh5DZVhawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2
+N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCH
+iZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hARe
+YFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1
+axwiP8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6g
+yN7igEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD
+AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPh
+ahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9V
+VE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0GCSqGSIb3DQEB
+BQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3Y
+IWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6Lzs
+QCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4
+ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qM
+YEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUb
+QErNaLly7HF27FSOH4UMAWr6pjisH8SE
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/ddc328ff.0 b/libcore/security/src/main/files/cacerts/ddc328ff.0
new file mode 100644
index 0000000..44d1bf6
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/ddc328ff.0
@@ -0,0 +1,56 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 1 (0x1)
+        Signature Algorithm: md5WithRSAEncryption
+        Issuer: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Server CA/emailAddress=server-certs@thawte.com
+        Validity
+            Not Before: Aug  1 00:00:00 1996 GMT
+            Not After : Dec 31 23:59:59 2020 GMT
+        Subject: C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting cc, OU=Certification Services Division, CN=Thawte Server CA/emailAddress=server-certs@thawte.com
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:d3:a4:50:6e:c8:ff:56:6b:e6:cf:5d:b6:ea:0c:
+                    68:75:47:a2:aa:c2:da:84:25:fc:a8:f4:47:51:da:
+                    85:b5:20:74:94:86:1e:0f:75:c9:e9:08:61:f5:06:
+                    6d:30:6e:15:19:02:e9:52:c0:62:db:4d:99:9e:e2:
+                    6a:0c:44:38:cd:fe:be:e3:64:09:70:c5:fe:b1:6b:
+                    29:b6:2f:49:c8:3b:d4:27:04:25:10:97:2f:e7:90:
+                    6d:c0:28:42:99:d7:4c:43:de:c3:f5:21:6d:54:9f:
+                    5d:c3:58:e1:c0:e4:d9:5b:b0:b8:dc:b4:7b:df:36:
+                    3a:c2:b5:66:22:12:d6:87:0d
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: md5WithRSAEncryption
+        07:fa:4c:69:5c:fb:95:cc:46:ee:85:83:4d:21:30:8e:ca:d9:
+        a8:6f:49:1a:e6:da:51:e3:60:70:6c:84:61:11:a1:1a:c8:48:
+        3e:59:43:7d:4f:95:3d:a1:8b:b7:0b:62:98:7a:75:8a:dd:88:
+        4e:4e:9e:40:db:a8:cc:32:74:b9:6f:0d:c6:e3:b3:44:0b:d9:
+        8a:6f:9a:29:9b:99:18:28:3b:d1:e3:40:28:9a:5a:3c:d5:b5:
+        e7:20:1b:8b:ca:a4:ab:8d:e9:51:d9:e2:4c:2c:59:a9:da:b9:
+        b2:75:1b:f6:42:f2:ef:c7:f2:18:f9:89:bc:a3:ff:8a:23:2e:
+        70:47
+SHA1 Fingerprint=23:E5:94:94:51:95:F2:41:48:03:B4:D5:64:D2:A3:A3:F5:D8:8B:8C
+-----BEGIN CERTIFICATE-----
+MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
+VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm
+MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx
+MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT
+DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3
+dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl
+cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3
+DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD
+gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91
+yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX
+L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj
+EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG
+7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e
+QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ
+qdq5snUb9kLy78fyGPmJvKP/iiMucEc=
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/e60bf0c0.0 b/libcore/security/src/main/files/cacerts/e60bf0c0.0
new file mode 100644
index 0000000..e999319
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/e60bf0c0.0
@@ -0,0 +1,128 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            5c:0b:85:5c:0b:e7:59:41:df:57:cc:3f:7f:9d:a8:36
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=ch, O=Swisscom, OU=Digital Certificate Services, CN=Swisscom Root CA 1
+        Validity
+            Not Before: Aug 18 12:06:20 2005 GMT
+            Not After : Aug 18 22:06:20 2025 GMT
+        Subject: C=ch, O=Swisscom, OU=Digital Certificate Services, CN=Swisscom Root CA 1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (4096 bit)
+                Modulus (4096 bit):
+                    00:d0:b9:b0:a8:0c:d9:bb:3f:21:f8:1b:d5:33:93:
+                    80:16:65:20:75:b2:3d:9b:60:6d:46:c8:8c:31:6f:
+                    17:c3:fa:9a:6c:56:ed:3c:c5:91:57:c3:cd:ab:96:
+                    49:90:2a:19:4b:1e:a3:6d:57:dd:f1:2b:62:28:75:
+                    45:5e:aa:d6:5b:fa:0b:25:d8:a1:16:f9:1c:c4:2e:
+                    e6:95:2a:67:cc:d0:29:6e:3c:85:34:38:61:49:b1:
+                    00:9f:d6:3a:71:5f:4d:6d:ce:5f:b9:a9:e4:89:7f:
+                    6a:52:fa:ca:9b:f2:dc:a9:f9:9d:99:47:3f:4e:29:
+                    5f:b4:a6:8d:5d:7b:0b:99:11:03:03:fe:e7:db:db:
+                    a3:ff:1d:a5:cd:90:1e:01:1f:35:b0:7f:00:db:90:
+                    6f:c6:7e:7b:d1:ee:7a:7a:a7:aa:0c:57:6f:a4:6d:
+                    c5:13:3b:b0:a5:d9:ed:32:1c:b4:5e:67:8b:54:dc:
+                    73:87:e5:d3:17:7c:66:50:72:5d:d4:1a:58:c1:d9:
+                    cf:d8:89:02:6f:a7:49:b4:36:5d:d0:a4:de:07:2c:
+                    b6:75:b7:28:91:d6:97:be:28:f5:98:1e:ea:5b:26:
+                    c9:bd:b0:97:73:da:ae:91:26:eb:68:c1:f9:39:15:
+                    d6:67:4b:0a:6d:4f:cb:cf:b0:e4:42:71:8c:53:79:
+                    e7:ee:e1:db:1d:a0:6e:1d:8c:1a:77:35:5c:16:1e:
+                    2b:53:1f:34:8b:d1:6c:fc:f2:67:07:7a:f5:ad:ed:
+                    d6:9a:ab:a1:b1:4b:e1:cc:37:5f:fd:7f:cd:4d:ae:
+                    b8:1f:9c:43:f9:2a:58:55:43:45:bc:96:cd:70:0e:
+                    fc:c9:e3:66:ba:4e:8d:3b:81:cb:15:64:7b:b9:94:
+                    e8:5d:33:52:85:71:2e:4f:8e:a2:06:11:51:c9:e3:
+                    cb:a1:6e:31:08:64:0c:c2:d2:3c:f5:36:e8:d7:d0:
+                    0e:78:23:20:91:c9:24:2a:65:29:5b:22:f7:21:ce:
+                    83:5e:a4:f3:de:4b:d3:68:8f:46:75:5c:83:09:6e:
+                    29:6b:c4:70:8c:f5:9d:d7:20:2f:ff:46:d2:2b:38:
+                    c2:2f:75:1c:3d:7e:da:a5:ef:1e:60:85:69:42:d3:
+                    cc:f8:63:fe:1e:43:39:85:a6:b6:63:41:10:b3:73:
+                    1e:bc:d3:fa:ca:7d:16:47:e2:a7:d5:d0:a3:8a:0a:
+                    08:96:62:56:6e:34:db:d9:02:b9:30:75:e3:04:d2:
+                    e7:8f:c2:b0:11:40:0a:ac:d5:71:02:62:8b:31:be:
+                    dd:c6:23:58:31:42:43:2d:74:f9:c6:9e:a6:8a:0f:
+                    e9:fe:bf:83:e6:43:57:24:ba:ef:46:34:aa:d7:12:
+                    01:38:ed
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Key Usage: critical
+                Digital Signature, Certificate Sign, CRL Sign
+            X509v3 Policy Mappings: 
+                2.16.756.1.83.0.1:2.16.756.1.83.0.1
+            X509v3 Basic Constraints: critical
+                CA:TRUE, pathlen:7
+            X509v3 Authority Key Identifier: 
+                keyid:03:25:2F:DE:6F:82:01:3A:5C:2C:DC:2B:A1:69:B5:67:D4:8C:D3:FD
+
+            X509v3 Subject Key Identifier: 
+                03:25:2F:DE:6F:82:01:3A:5C:2C:DC:2B:A1:69:B5:67:D4:8C:D3:FD
+    Signature Algorithm: sha1WithRSAEncryption
+        35:10:cb:ec:a6:04:0d:0d:0f:cd:c0:db:ab:a8:f2:88:97:0c:
+        df:93:2f:4d:7c:40:56:31:7a:eb:a4:0f:60:cd:7a:f3:be:c3:
+        27:8e:03:3e:a4:dd:12:ef:7e:1e:74:06:3c:3f:31:f2:1c:7b:
+        91:31:21:b4:f0:d0:6c:97:d4:e9:97:b2:24:56:1e:56:c3:35:
+        bd:88:05:0f:5b:10:1a:64:e1:c7:82:30:f9:32:ad:9e:50:2c:
+        e7:78:05:d0:31:b1:5a:98:8a:75:4e:90:5c:6a:14:2a:e0:52:
+        47:82:60:e6:1e:da:81:b1:fb:14:0b:5a:f1:9f:d2:95:ba:3e:
+        d0:1b:d6:15:1d:a3:be:86:d5:db:0f:c0:49:64:bb:2e:50:19:
+        4b:d2:24:f8:dd:1e:07:56:d0:38:a0:95:70:20:76:8c:d7:dd:
+        1e:de:9f:71:c4:23:ef:83:13:5c:a3:24:15:4d:29:40:3c:6a:
+        c4:a9:d8:b7:a6:44:a5:0d:f4:e0:9d:77:1e:40:70:26:fc:da:
+        d9:36:e4:79:e4:b5:3f:bc:9b:65:be:bb:11:96:cf:db:c6:28:
+        39:3a:08:ce:47:5b:53:5a:c5:99:fe:5d:a9:dd:ef:4c:d4:c6:
+        a5:ad:02:e6:8c:07:12:1e:6f:03:d1:6f:a0:a3:f3:29:bd:12:
+        c7:50:a2:b0:7f:88:a9:99:77:9a:b1:c0:a5:39:2e:5c:7c:69:
+        e2:2c:b0:ea:37:6a:a4:e1:5a:e1:f5:50:e5:83:ef:a5:bb:2a:
+        88:e7:8c:db:fd:6d:5e:97:19:a8:7e:66:75:6b:71:ea:bf:b1:
+        c7:6f:a0:f4:8e:a4:ec:34:51:5b:8c:26:03:70:a1:77:d5:01:
+        12:57:00:35:db:23:de:0e:8a:28:99:fd:b1:10:6f:4b:ff:38:
+        2d:60:4e:2c:9c:eb:67:b5:ad:49:ee:4b:1f:ac:af:fb:0d:90:
+        5a:66:60:70:5d:aa:cd:78:d4:24:ee:c8:41:a0:93:01:92:9c:
+        6a:9e:fc:b9:24:c5:b3:15:82:7e:be:ae:95:2b:eb:b1:c0:da:
+        e3:01:60:0b:5e:69:ac:84:56:61:be:71:17:fe:1d:13:0f:fe:
+        c6:87:45:e9:fe:32:a0:1a:0d:13:a4:94:55:71:a5:16:8b:ba:
+        ca:89:b0:b2:c7:fc:8f:d8:54:b5:93:62:9d:ce:cf:59:fb:3d:
+        18:ce:2a:cb:35:15:82:5d:ff:54:22:5b:71:52:fb:b7:c9:fe:
+        60:9b:00:41:64:f0:aa:2a:ec:b6:42:43:ce:89:66:81:c8:8b:
+        9f:39:54:03:25:d3:16:35:8e:84:d0:5f:fa:30:1a:f5:9a:6c:
+        f4:0e:53:f9:3a:5b:d1:1c
+SHA1 Fingerprint=5F:3A:FC:0A:8B:64:F6:86:67:34:74:DF:7E:A9:A2:FE:F9:FA:7A:51
+-----BEGIN CERTIFICATE-----
+MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBk
+MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0
+YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg
+Q0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4MTgyMjA2MjBaMGQxCzAJBgNVBAYT
+AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp
+Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIICIjAN
+BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9
+m2BtRsiMMW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdih
+FvkcxC7mlSpnzNApbjyFNDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/
+TilftKaNXXsLmREDA/7n29uj/x2lzZAeAR81sH8A25Bvxn570e56eqeqDFdvpG3F
+EzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkCb6dJtDZd0KTeByy2dbco
+kdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn7uHbHaBu
+HYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNF
+vJbNcA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo
+19AOeCMgkckkKmUpWyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjC
+L3UcPX7ape8eYIVpQtPM+GP+HkM5haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJW
+bjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNYMUJDLXT5xp6mig/p/r+D5kNX
+JLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw
+FDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j
+BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzc
+K6FptWfUjNP9MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzf
+ky9NfEBWMXrrpA9gzXrzvsMnjgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7Ik
+Vh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQMbFamIp1TpBcahQq4FJHgmDmHtqB
+sfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4HVtA4oJVwIHaM190e
+3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtlvrsR
+ls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ip
+mXeascClOS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HH
+b6D0jqTsNFFbjCYDcKF31QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksf
+rK/7DZBaZmBwXarNeNQk7shBoJMBkpxqnvy5JMWzFYJ+vq6VK+uxwNrjAWALXmms
+hFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCyx/yP2FS1k2Kdzs9Z+z0Y
+zirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMWNY6E0F/6
+MBr1mmz0DlP5OlvRHA==
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/e7b8d656.0 b/libcore/security/src/main/files/cacerts/e7b8d656.0
new file mode 100644
index 0000000..ad22897
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/e7b8d656.0
@@ -0,0 +1,60 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 4 (0x4)
+        Signature Algorithm: md5WithRSAEncryption
+        Issuer: C=US, O=Equifax Secure Inc., CN=Equifax Secure eBusiness CA-1
+        Validity
+            Not Before: Jun 21 04:00:00 1999 GMT
+            Not After : Jun 21 04:00:00 2020 GMT
+        Subject: C=US, O=Equifax Secure Inc., CN=Equifax Secure eBusiness CA-1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:ce:2f:19:bc:17:b7:77:de:93:a9:5f:5a:0d:17:
+                    4f:34:1a:0c:98:f4:22:d9:59:d4:c4:68:46:f0:b4:
+                    35:c5:85:03:20:c6:af:45:a5:21:51:45:41:eb:16:
+                    58:36:32:6f:e2:50:62:64:f9:fd:51:9c:aa:24:d9:
+                    f4:9d:83:2a:87:0a:21:d3:12:38:34:6c:8d:00:6e:
+                    5a:a0:d9:42:ee:1a:21:95:f9:52:4c:55:5a:c5:0f:
+                    38:4f:46:fa:6d:f8:2e:35:d6:1d:7c:eb:e2:f0:b0:
+                    75:80:c8:a9:13:ac:be:88:ef:3a:6e:ab:5f:2a:38:
+                    62:02:b0:12:7b:fe:8f:a6:03
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            Netscape Cert Type: 
+                SSL CA, S/MIME CA, Object Signing CA
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            X509v3 Authority Key Identifier: 
+                keyid:4A:78:32:52:11:DB:59:16:36:5E:DF:C1:14:36:40:6A:47:7C:4C:A1
+
+            X509v3 Subject Key Identifier: 
+                4A:78:32:52:11:DB:59:16:36:5E:DF:C1:14:36:40:6A:47:7C:4C:A1
+    Signature Algorithm: md5WithRSAEncryption
+        75:5b:a8:9b:03:11:e6:e9:56:4c:cd:f9:a9:4c:c0:0d:9a:f3:
+        cc:65:69:e6:25:76:cc:59:b7:d6:54:c3:1d:cd:99:ac:19:dd:
+        b4:85:d5:e0:3d:fc:62:20:a7:84:4b:58:65:f1:e2:f9:95:21:
+        3f:f5:d4:7e:58:1e:47:87:54:3e:58:a1:b5:b5:f8:2a:ef:71:
+        e7:bc:c3:f6:b1:49:46:e2:d7:a0:6b:e5:56:7a:9a:27:98:7c:
+        46:62:14:e7:c9:fc:6e:03:12:79:80:38:1d:48:82:8d:fc:17:
+        fe:2a:96:2b:b5:62:a6:a6:3d:bd:7f:92:59:cd:5a:2a:82:b2:
+        37:79
+SHA1 Fingerprint=DA:40:18:8B:91:89:A3:ED:EE:AE:DA:97:FE:2F:9D:F5:B7:D1:8A:41
+-----BEGIN CERTIFICATE-----
+MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT
+ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw
+MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j
+LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ
+KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo
+RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu
+WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw
+Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD
+AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK
+eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM
+zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+
+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN
+/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ==
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/ed524cf5.0 b/libcore/security/src/main/files/cacerts/ed524cf5.0
new file mode 100644
index 0000000..8dc3661
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/ed524cf5.0
@@ -0,0 +1,83 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 927650371 (0x374ad243)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=US, O=Entrust.net, OU=www.entrust.net/CPS incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Secure Server Certification Authority
+        Validity
+            Not Before: May 25 16:09:40 1999 GMT
+            Not After : May 25 16:39:40 2019 GMT
+        Subject: C=US, O=Entrust.net, OU=www.entrust.net/CPS incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Secure Server Certification Authority
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:cd:28:83:34:54:1b:89:f3:0f:af:37:91:31:ff:
+                    af:31:60:c9:a8:e8:b2:10:68:ed:9f:e7:93:36:f1:
+                    0a:64:bb:47:f5:04:17:3f:23:47:4d:c5:27:19:81:
+                    26:0c:54:72:0d:88:2d:d9:1f:9a:12:9f:bc:b3:71:
+                    d3:80:19:3f:47:66:7b:8c:35:28:d2:b9:0a:df:24:
+                    da:9c:d6:50:79:81:7a:5a:d3:37:f7:c2:4a:d8:29:
+                    92:26:64:d1:e4:98:6c:3a:00:8a:f5:34:9b:65:f8:
+                    ed:e3:10:ff:fd:b8:49:58:dc:a0:de:82:39:6b:81:
+                    b1:16:19:61:b9:54:b6:e6:43
+                Exponent: 3 (0x3)
+        X509v3 extensions:
+            Netscape Cert Type: 
+                SSL CA, S/MIME CA, Object Signing CA
+            X509v3 CRL Distribution Points: 
+                DirName:/C=US/O=Entrust.net/OU=www.entrust.net/CPS incorp. by ref. (limits liab.)/OU=(c) 1999 Entrust.net Limited/CN=Entrust.net Secure Server Certification Authority/CN=CRL1
+                URI:http://www.entrust.net/CRL/net1.crl
+
+            X509v3 Private Key Usage Period: 
+                Not Before: May 25 16:09:40 1999 GMT, Not After: May 25 16:09:40 2019 GMT
+            X509v3 Key Usage: 
+                Certificate Sign, CRL Sign
+            X509v3 Authority Key Identifier: 
+                keyid:F0:17:62:13:55:3D:B3:FF:0A:00:6B:FB:50:84:97:F3:ED:62:D0:1A
+
+            X509v3 Subject Key Identifier: 
+                F0:17:62:13:55:3D:B3:FF:0A:00:6B:FB:50:84:97:F3:ED:62:D0:1A
+            X509v3 Basic Constraints: 
+                CA:TRUE
+            1.2.840.113533.7.65.0: 
+                0
+..V4.0....
+    Signature Algorithm: sha1WithRSAEncryption
+        90:dc:30:02:fa:64:74:c2:a7:0a:a5:7c:21:8d:34:17:a8:fb:
+        47:0e:ff:25:7c:8d:13:0a:fb:e4:98:b5:ef:8c:f8:c5:10:0d:
+        f7:92:be:f1:c3:d5:d5:95:6a:04:bb:2c:ce:26:36:65:c8:31:
+        c6:e7:ee:3f:e3:57:75:84:7a:11:ef:46:4f:18:f4:d3:98:bb:
+        a8:87:32:ba:72:f6:3c:e2:3d:9f:d7:1d:d9:c3:60:43:8c:58:
+        0e:22:96:2f:62:a3:2c:1f:ba:ad:05:ef:ab:32:78:87:a0:54:
+        73:19:b5:5c:05:f9:52:3e:6d:2d:45:0b:f7:0a:93:ea:ed:06:
+        f9:b2
+SHA1 Fingerprint=99:A6:9B:E6:1A:FE:88:6B:4D:2B:82:00:7C:B8:54:FC:31:7E:15:39
+-----BEGIN CERTIFICATE-----
+MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC
+VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u
+ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc
+KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u
+ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1
+MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE
+ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j
+b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF
+bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg
+U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA
+A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/
+I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3
+wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC
+AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb
+oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5
+BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p
+dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk
+MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp
+b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu
+dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0
+MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi
+E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa
+MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI
+hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN
+95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd
+2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/ee7cd6fb.0 b/libcore/security/src/main/files/cacerts/ee7cd6fb.0
new file mode 100644
index 0000000..8fdba37
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/ee7cd6fb.0
@@ -0,0 +1,98 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 0 (0x0)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=EU, O=AC Camerfirma SA CIF A82743287, OU=http://www.chambersign.org, CN=Chambers of Commerce Root
+        Validity
+            Not Before: Sep 30 16:13:43 2003 GMT
+            Not After : Sep 30 16:13:44 2037 GMT
+        Subject: C=EU, O=AC Camerfirma SA CIF A82743287, OU=http://www.chambersign.org, CN=Chambers of Commerce Root
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:b7:36:55:e5:a5:5d:18:30:e0:da:89:54:91:fc:
+                    c8:c7:52:f8:2f:50:d9:ef:b1:75:73:65:47:7d:1b:
+                    5b:ba:75:c5:fc:a1:88:24:fa:2f:ed:ca:08:4a:39:
+                    54:c4:51:7a:b5:da:60:ea:38:3c:81:b2:cb:f1:bb:
+                    d9:91:23:3f:48:01:70:75:a9:05:2a:ad:1f:71:f3:
+                    c9:54:3d:1d:06:6a:40:3e:b3:0c:85:ee:5c:1b:79:
+                    c2:62:c4:b8:36:8e:35:5d:01:0c:23:04:47:35:aa:
+                    9b:60:4e:a0:66:3d:cb:26:0a:9c:40:a1:f4:5d:98:
+                    bf:71:ab:a5:00:68:2a:ed:83:7a:0f:a2:14:b5:d4:
+                    22:b3:80:b0:3c:0c:5a:51:69:2d:58:18:8f:ed:99:
+                    9e:f1:ae:e2:95:e6:f6:47:a8:d6:0c:0f:b0:58:58:
+                    db:c3:66:37:9e:9b:91:54:33:37:d2:94:1c:6a:48:
+                    c9:c9:f2:a5:da:a5:0c:23:f7:23:0e:9c:32:55:5e:
+                    71:9c:84:05:51:9a:2d:fd:e6:4e:2a:34:5a:de:ca:
+                    40:37:67:0c:54:21:55:77:da:0a:0c:cc:97:ae:80:
+                    dc:94:36:4a:f4:3e:ce:36:13:1e:53:e4:ac:4e:3a:
+                    05:ec:db:ae:72:9c:38:8b:d0:39:3b:89:0a:3e:77:
+                    fe:75
+                Exponent: 3 (0x3)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:TRUE, pathlen:12
+            X509v3 CRL Distribution Points: 
+                URI:http://crl.chambersign.org/chambersroot.crl
+
+            X509v3 Subject Key Identifier: 
+                E3:94:F5:B1:4D:E9:DB:A1:29:5B:57:8B:4D:76:06:76:E1:D1:A2:8A
+            X509v3 Key Usage: critical
+                Certificate Sign, CRL Sign
+            Netscape Cert Type: 
+                SSL CA, S/MIME CA, Object Signing CA
+            X509v3 Subject Alternative Name: 
+                email:chambersroot@chambersign.org
+            X509v3 Issuer Alternative Name: 
+                email:chambersroot@chambersign.org
+            X509v3 Certificate Policies: 
+                Policy: 1.3.6.1.4.1.17326.10.3.1
+                  CPS: http://cps.chambersign.org/cps/chambersroot.html
+
+    Signature Algorithm: sha1WithRSAEncryption
+        0c:41:97:c2:1a:86:c0:22:7c:9f:fb:90:f3:1a:d1:03:b1:ef:
+        13:f9:21:5f:04:9c:da:c9:a5:8d:27:6c:96:87:91:be:41:90:
+        01:72:93:e7:1e:7d:5f:f6:89:c6:5d:a7:40:09:3d:ac:49:45:
+        45:dc:2e:8d:30:68:b2:09:ba:fb:c3:2f:cc:ba:0b:df:3f:77:
+        7b:46:7d:3a:12:24:8e:96:8f:3c:05:0a:6f:d2:94:28:1d:6d:
+        0c:c0:2e:88:22:d5:d8:cf:1d:13:c7:f0:48:d7:d7:05:a7:cf:
+        c7:47:9e:3b:3c:34:c8:80:4f:d4:14:bb:fc:0d:50:f7:fa:b3:
+        ec:42:5f:a9:dd:6d:c8:f4:75:cf:7b:c1:72:26:b1:01:1c:5c:
+        2c:fd:7a:4e:b4:01:c5:05:57:b9:e7:3c:aa:05:d9:88:e9:07:
+        46:41:ce:ef:41:81:ae:58:df:83:a2:ae:ca:d7:77:1f:e7:00:
+        3c:9d:6f:8e:e4:32:09:1d:4d:78:34:78:34:3c:94:9b:26:ed:
+        4f:71:c6:19:7a:bd:20:22:48:5a:fe:4b:7d:03:b7:e7:58:be:
+        c6:32:4e:74:1e:68:dd:a8:68:5b:b3:3e:ee:62:7d:d9:80:e8:
+        0a:75:7a:b7:ee:b4:65:9a:21:90:e0:aa:d0:98:bc:38:b5:73:
+        3c:8b:f8:dc
+SHA1 Fingerprint=6E:3A:55:A4:19:0C:19:5C:93:84:3C:C0:DB:72:2E:31:30:61:F0:B1
+-----BEGIN CERTIFICATE-----
+MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn
+MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL
+ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg
+b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa
+MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB
+ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw
+IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B
+AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb
+unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d
+BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq
+7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3
+0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX
+roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG
+A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j
+aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p
+26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA
+BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud
+EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN
+BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz
+aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB
+AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd
+p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi
+1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc
+XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0
+eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu
+tGWaIZDgqtCYvDi1czyL+Nw=
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/f4996e82.0 b/libcore/security/src/main/files/cacerts/f4996e82.0
new file mode 100644
index 0000000..a7c89d1
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/f4996e82.0
@@ -0,0 +1,52 @@
+Certificate:
+    Data:
+        Version: 1 (0x0)
+        Serial Number: 1 (0x1)
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: L=ValiCert Validation Network, O=ValiCert, Inc., OU=ValiCert Class 1 Policy Validation Authority, CN=http://www.valicert.com//emailAddress=info@valicert.com
+        Validity
+            Not Before: Jun 25 22:23:48 1999 GMT
+            Not After : Jun 25 22:23:48 2019 GMT
+        Subject: L=ValiCert Validation Network, O=ValiCert, Inc., OU=ValiCert Class 1 Policy Validation Authority, CN=http://www.valicert.com//emailAddress=info@valicert.com
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:d8:59:82:7a:89:b8:96:ba:a6:2f:68:6f:58:2e:
+                    a7:54:1c:06:6e:f4:ea:8d:48:bc:31:94:17:f0:f3:
+                    4e:bc:b2:b8:35:92:76:b0:d0:a5:a5:01:d7:00:03:
+                    12:22:19:08:f8:ff:11:23:9b:ce:07:f5:bf:69:1a:
+                    26:fe:4e:e9:d1:7f:9d:2c:40:1d:59:68:6e:a6:f8:
+                    58:b0:9d:1a:8f:d3:3f:f1:dc:19:06:81:a8:0e:e0:
+                    3a:dd:c8:53:45:09:06:e6:0f:70:c3:fa:40:a6:0e:
+                    e2:56:05:0f:18:4d:fc:20:82:d1:73:55:74:8d:76:
+                    72:a0:1d:9d:1d:c0:dd:3f:71
+                Exponent: 65537 (0x10001)
+    Signature Algorithm: sha1WithRSAEncryption
+        50:68:3d:49:f4:2c:1c:06:94:df:95:60:7f:96:7b:17:fe:4f:
+        71:ad:64:c8:dd:77:d2:ef:59:55:e8:3f:e8:8e:05:2a:21:f2:
+        07:d2:b5:a7:52:fe:9c:b1:b6:e2:5b:77:17:40:ea:72:d6:23:
+        cb:28:81:32:c3:00:79:18:ec:59:17:89:c9:c6:6a:1e:71:c9:
+        fd:b7:74:a5:25:45:69:c5:48:ab:19:e1:45:8a:25:6b:19:ee:
+        e5:bb:12:f5:7f:f7:a6:8d:51:c3:f0:9d:74:b7:a9:3e:a0:a5:
+        ff:b6:49:03:13:da:22:cc:ed:71:82:2b:99:cf:3a:b7:f5:2d:
+        72:c8
+SHA1 Fingerprint=E5:DF:74:3C:B6:01:C4:9B:98:43:DC:AB:8C:E8:6A:81:10:9F:E4:8E
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIyMjM0OFoXDTE5MDYy
+NTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9Y
+LqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+
+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8Y
+TfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0
+LBwGlN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLW
+I8sogTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw
+nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/f64d9715.0 b/libcore/security/src/main/files/cacerts/f64d9715.0
new file mode 100644
index 0000000..5bd0126
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/f64d9715.0
@@ -0,0 +1,51 @@
+Certificate:
+    Data:
+        Version: 1 (0x0)
+        Serial Number: 0 (0x0)
+        Signature Algorithm: md5WithRSAEncryption
+        Issuer: C=ES, ST=BARCELONA, L=BARCELONA, O=IPS Seguridad CA, OU=Certificaciones, CN=IPS SERVIDORES/emailAddress=ips@mail.ips.es
+        Validity
+            Not Before: Jan  1 23:21:07 1998 GMT
+            Not After : Dec 29 23:21:07 2009 GMT
+        Subject: C=ES, ST=BARCELONA, L=BARCELONA, O=IPS Seguridad CA, OU=Certificaciones, CN=IPS SERVIDORES/emailAddress=ips@mail.ips.es
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:ac:4f:52:74:9f:39:ea:8e:dc:25:c4:bc:98:5d:
+                    98:64:24:09:3c:21:b3:cc:19:b5:8e:94:8e:87:d1:
+                    f8:37:3e:a1:c8:2d:58:a4:80:35:5b:a1:75:6c:1d:
+                    45:0c:1f:61:63:6a:5e:6f:9b:0a:4c:c1:c8:b8:61:
+                    23:35:81:ff:fe:ac:78:70:2d:68:e1:3a:07:98:95:
+                    02:54:dd:cd:23:b7:80:53:d7:c8:37:45:72:06:24:
+                    12:ba:13:61:21:8a:6e:75:28:e0:c5:0f:34:fd:36:
+                    d8:45:7f:e1:b8:36:ef:b3:e1:c6:20:8e:e8:b4:38:
+                    bc:e1:3e:f6:11:de:8c:9d:01
+                Exponent: 65537 (0x10001)
+    Signature Algorithm: md5WithRSAEncryption
+        2c:f3:c3:79:58:24:de:c6:3b:d1:e0:42:69:b8:ee:64:b3:3d:
+        62:01:b9:b3:84:df:23:7d:dd:98:cf:10:a9:fe:00:d8:22:96:
+        05:13:07:54:57:c5:a7:de:cb:d9:b8:88:42:f6:99:db:14:77:
+        1f:b6:fe:25:3d:e1:a2:3e:03:a9:81:d2:2d:6c:47:f5:96:46:
+        8c:22:ab:c8:cc:0d:0e:97:5e:8b:41:b4:3b:c4:0a:06:40:1d:
+        dd:46:f4:01:dd:ba:82:2e:3c:3d:78:70:9e:7c:18:d0:ab:f8:
+        b8:77:07:46:71:f1:ca:0b:63:5c:6a:f9:72:94:d5:01:4f:a0:
+        db:42
+SHA1 Fingerprint=24:BA:6D:6C:8A:5B:58:37:A4:8D:B5:FA:E9:19:EA:67:5C:94:D2:17
+-----BEGIN CERTIFICATE-----
+MIICtzCCAiACAQAwDQYJKoZIhvcNAQEEBQAwgaMxCzAJBgNVBAYTAkVTMRIwEAYD
+VQQIEwlCQVJDRUxPTkExEjAQBgNVBAcTCUJBUkNFTE9OQTEZMBcGA1UEChMQSVBT
+IFNlZ3VyaWRhZCBDQTEYMBYGA1UECxMPQ2VydGlmaWNhY2lvbmVzMRcwFQYDVQQD
+Ew5JUFMgU0VSVklET1JFUzEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVz
+MB4XDTk4MDEwMTIzMjEwN1oXDTA5MTIyOTIzMjEwN1owgaMxCzAJBgNVBAYTAkVT
+MRIwEAYDVQQIEwlCQVJDRUxPTkExEjAQBgNVBAcTCUJBUkNFTE9OQTEZMBcGA1UE
+ChMQSVBTIFNlZ3VyaWRhZCBDQTEYMBYGA1UECxMPQ2VydGlmaWNhY2lvbmVzMRcw
+FQYDVQQDEw5JUFMgU0VSVklET1JFUzEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwu
+aXBzLmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsT1J0nznqjtwlxLyY
+XZhkJAk8IbPMGbWOlI6H0fg3PqHILVikgDVboXVsHUUMH2Fjal5vmwpMwci4YSM1
+gf/+rHhwLWjhOgeYlQJU3c0jt4BT18g3RXIGJBK6E2Ehim51KODFDzT9NthFf+G4
+Nu+z4cYgjui0OLzhPvYR3oydAQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBACzzw3lY
+JN7GO9HgQmm47mSzPWIBubOE3yN93ZjPEKn+ANgilgUTB1RXxafey9m4iEL2mdsU
+dx+2/iU94aI+A6mB0i1sR/WWRowiq8jMDQ6XXotBtDvECgZAHd1G9AHduoIuPD14
+cJ58GNCr+Lh3B0Zx8coLY1xq+XKU1QFPoNtC
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/f73e89fd.0 b/libcore/security/src/main/files/cacerts/f73e89fd.0
new file mode 100644
index 0000000..8e9595e
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/f73e89fd.0
@@ -0,0 +1,48 @@
+Certificate:
+    Data:
+        Version: 1 (0x0)
+        Serial Number:
+            02:ad:66:7e:4e:45:fe:5e:57:6f:3c:98:19:5e:dd:c0
+        Signature Algorithm: md2WithRSAEncryption
+        Issuer: C=US, O=RSA Data Security, Inc., OU=Secure Server Certification Authority
+        Validity
+            Not Before: Nov  9 00:00:00 1994 GMT
+            Not After : Jan  7 23:59:59 2010 GMT
+        Subject: C=US, O=RSA Data Security, Inc., OU=Secure Server Certification Authority
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1000 bit)
+                Modulus (1000 bit):
+                    00:92:ce:7a:c1:ae:83:3e:5a:aa:89:83:57:ac:25:
+                    01:76:0c:ad:ae:8e:2c:37:ce:eb:35:78:64:54:03:
+                    e5:84:40:51:c9:bf:8f:08:e2:8a:82:08:d2:16:86:
+                    37:55:e9:b1:21:02:ad:76:68:81:9a:05:a2:4b:c9:
+                    4b:25:66:22:56:6c:88:07:8f:f7:81:59:6d:84:07:
+                    65:70:13:71:76:3e:9b:77:4c:e3:50:89:56:98:48:
+                    b9:1d:a7:29:1a:13:2e:4a:11:59:9c:1e:15:d5:49:
+                    54:2c:73:3a:69:82:b1:97:39:9c:6d:70:67:48:e5:
+                    dd:2d:d6:c8:1e:7b
+                Exponent: 65537 (0x10001)
+    Signature Algorithm: md2WithRSAEncryption
+        65:dd:7e:e1:b2:ec:b0:e2:3a:e0:ec:71:46:9a:19:11:b8:d3:
+        c7:a0:b4:03:40:26:02:3e:09:9c:e1:12:b3:d1:5a:f6:37:a5:
+        b7:61:03:b6:5b:16:69:3b:c6:44:08:0c:88:53:0c:6b:97:49:
+        c7:3e:35:dc:6c:b9:bb:aa:df:5c:bb:3a:2f:93:60:b6:a9:4b:
+        4d:f2:20:f7:cd:5f:7f:64:7b:8e:dc:00:5c:d7:fa:77:ca:39:
+        16:59:6f:0e:ea:d3:b5:83:7f:4d:4d:42:56:76:b4:c9:5f:04:
+        f8:38:f8:eb:d2:5f:75:5f:cd:7b:fc:e5:8e:80:7c:fc:50
+SHA1 Fingerprint=44:63:C5:31:D7:CC:C1:00:67:94:61:2B:B6:56:D3:BF:82:57:84:6F
+-----BEGIN CERTIFICATE-----
+MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzELMAkG
+A1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD
+VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk0
+MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UEBhMCVVMxIDAeBgNV
+BAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2Vy
+dmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGbMA0GCSqGSIb3DQEBAQUAA4GJ
+ADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6OLDfO6zV4ZFQD5YRAUcm/jwjiioII
+0haGN1XpsSECrXZogZoFokvJSyVmIlZsiAeP94FZbYQHZXATcXY+m3dM41CJVphI
+uR2nKRoTLkoRWZweFdVJVCxzOmmCsZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZI
+hvcNAQECBQADfgBl3X7hsuyw4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3
+YQO2WxZpO8ZECAyIUwxrl0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc
+1/p3yjkWWW8O6tO1g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA==
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/cacerts/ff783690.0 b/libcore/security/src/main/files/cacerts/ff783690.0
new file mode 100644
index 0000000..2c11e52
--- /dev/null
+++ b/libcore/security/src/main/files/cacerts/ff783690.0
@@ -0,0 +1,89 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            44:be:0c:8b:50:00:24:b4:11:d3:36:2a:fe:65:0a:fd
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=US, ST=UT, L=Salt Lake City, O=The USERTRUST Network, OU=http://www.usertrust.com, CN=UTN-USERFirst-Hardware
+        Validity
+            Not Before: Jul  9 18:10:42 1999 GMT
+            Not After : Jul  9 18:19:22 2019 GMT
+        Subject: C=US, ST=UT, L=Salt Lake City, O=The USERTRUST Network, OU=http://www.usertrust.com, CN=UTN-USERFirst-Hardware
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:b1:f7:c3:38:3f:b4:a8:7f:cf:39:82:51:67:d0:
+                    6d:9f:d2:ff:58:f3:e7:9f:2b:ec:0d:89:54:99:b9:
+                    38:99:16:f7:e0:21:79:48:c2:bb:61:74:12:96:1d:
+                    3c:6a:72:d5:3c:10:67:3a:39:ed:2b:13:cd:66:eb:
+                    95:09:33:a4:6c:97:b1:e8:c6:ec:c1:75:79:9c:46:
+                    5e:8d:ab:d0:6a:fd:b9:2a:55:17:10:54:b3:19:f0:
+                    9a:f6:f1:b1:5d:b6:a7:6d:fb:e0:71:17:6b:a2:88:
+                    fb:00:df:fe:1a:31:77:0c:9a:01:7a:b1:32:e3:2b:
+                    01:07:38:6e:c3:a5:5e:23:bc:45:9b:7b:50:c1:c9:
+                    30:8f:db:e5:2b:7a:d3:5b:fb:33:40:1e:a0:d5:98:
+                    17:bc:8b:87:c3:89:d3:5d:a0:8e:b2:aa:aa:f6:8e:
+                    69:88:06:c5:fa:89:21:f3:08:9d:69:2e:09:33:9b:
+                    29:0d:46:0f:8c:cc:49:34:b0:69:51:bd:f9:06:cd:
+                    68:ad:66:4c:bc:3e:ac:61:bd:0a:88:0e:c8:df:3d:
+                    ee:7c:04:4c:9d:0a:5e:6b:91:d6:ee:c7:ed:28:8d:
+                    ab:4d:87:89:73:d0:6e:a4:d0:1e:16:8b:14:e1:76:
+                    44:03:7f:63:ac:e4:cd:49:9c:c5:92:f4:ab:32:a1:
+                    48:5b
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Key Usage: 
+                Digital Signature, Non Repudiation, Certificate Sign, CRL Sign
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+            X509v3 Subject Key Identifier: 
+                A1:72:5F:26:1B:28:98:43:95:5D:07:37:D5:85:96:9D:4B:D2:C3:45
+            X509v3 CRL Distribution Points: 
+                URI:http://crl.usertrust.com/UTN-USERFirst-Hardware.crl
+
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication, IPSec End System, IPSec Tunnel, IPSec User
+    Signature Algorithm: sha1WithRSAEncryption
+        47:19:0f:de:74:c6:99:97:af:fc:ad:28:5e:75:8e:eb:2d:67:
+        ee:4e:7b:2b:d7:0c:ff:f6:de:cb:55:a2:0a:e1:4c:54:65:93:
+        60:6b:9f:12:9c:ad:5e:83:2c:eb:5a:ae:c0:e4:2d:f4:00:63:
+        1d:b8:c0:6c:f2:cf:49:bb:4d:93:6f:06:a6:0a:22:b2:49:62:
+        08:4e:ff:c8:c8:14:b2:88:16:5d:e7:01:e4:12:95:e5:45:34:
+        b3:8b:69:bd:cf:b4:85:8f:75:51:9e:7d:3a:38:3a:14:48:12:
+        c6:fb:a7:3b:1a:8d:0d:82:40:07:e8:04:08:90:a1:89:cb:19:
+        50:df:ca:1c:01:bc:1d:04:19:7b:10:76:97:3b:ee:90:90:ca:
+        c4:0e:1f:16:6e:75:ef:33:f8:d3:6f:5b:1e:96:e3:e0:74:77:
+        74:7b:8a:a2:6e:2d:dd:76:d6:39:30:82:f0:ab:9c:52:f2:2a:
+        c7:af:49:5e:7e:c7:68:e5:82:81:c8:6a:27:f9:27:88:2a:d5:
+        58:50:95:1f:f0:3b:1c:57:bb:7d:14:39:62:2b:9a:c9:94:92:
+        2a:a3:22:0c:ff:89:26:7d:5f:23:2b:47:d7:15:1d:a9:6a:9e:
+        51:0d:2a:51:9e:81:f9:d4:3b:5e:70:12:7f:10:32:9c:1e:bb:
+        9d:f8:66:a8
+SHA1 Fingerprint=04:83:ED:33:99:AC:36:08:05:87:22:ED:BC:5E:46:00:E3:BE:F9:D7
+-----BEGIN CERTIFICATE-----
+MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB
+lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
+SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG
+A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe
+MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v
+d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh
+cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn
+0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ
+M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a
+MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd
+oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI
+DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy
+oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD
+VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0
+dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy
+bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF
+BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
+//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli
+CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE
+CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t
+3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS
+KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==
+-----END CERTIFICATE-----
diff --git a/libcore/security/src/main/files/certimport.sh b/libcore/security/src/main/files/certimport.sh
new file mode 100755
index 0000000..fe3f943
--- /dev/null
+++ b/libcore/security/src/main/files/certimport.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+# This script was tested to work with bouncycastle 1.32.
+#
+# (NOTE: keytool does not pick up bouncycastle's jce provider jar
+#  unless it is installed under the system jar directory)
+
+set -x
+set -e
+
+CERTSTORE=cacerts.bks
+
+if [ -a $CERTSTORE ]; then
+    rm $CERTSTORE || exit 1
+fi
+
+if [ -z "$STOREPASS" ]; then
+    STOREPASS=changeit
+fi
+
+COUNTER=0
+for cert in `ls -1 cacerts`
+  do
+  yes | keytool \
+      -import \
+      -v \
+      -trustcacerts \
+      -alias $COUNTER \
+      -file <(openssl x509 -in cacerts/$cert) \
+      -keystore $CERTSTORE \
+      -storetype BKS \
+      -provider org.bouncycastle.jce.provider.BouncyCastleProvider \
+      -storepass $STOREPASS
+  let "COUNTER=$COUNTER + 1"
+done
diff --git a/libcore/security/src/main/java/java/security/AccessControlException.java b/libcore/security/src/main/java/java/security/AccessControlException.java
new file mode 100644
index 0000000..31968c0
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/AccessControlException.java
@@ -0,0 +1,75 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Astapchuk
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * This runtime exception is thrown when an access control check indicates that
+ * access should not be granted.
+ * 
+ */
+public class AccessControlException extends SecurityException {
+
+    private static final long serialVersionUID = 5138225684096988535L;
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    private Permission perm; // Named as demanded by Serialized Form.
+
+    /**
+     * Constructs a new instance of this class with its walkback and message
+     * filled in.
+     * 
+     * 
+     * @param message
+     *            String The detail message for the exception.
+     */
+    public AccessControlException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new instance of this class with its walkback, message and
+     * associated permission all filled in.
+     * 
+     * 
+     * @param message
+     *            String The detail message for the exception.
+     * @param perm
+     *            Permission The failed permission.
+     */
+    public AccessControlException(String message, Permission perm) {
+        super(message);
+        this.perm = perm;
+    }
+
+    /**
+     * Returns the receiver's permission.
+     * 
+     * 
+     * @return Permission the receiver's permission
+     */
+    public Permission getPermission() {
+        return perm;
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/AlgorithmParameterGenerator.java b/libcore/security/src/main/java/java/security/AlgorithmParameterGenerator.java
new file mode 100644
index 0000000..7c10354
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/AlgorithmParameterGenerator.java
@@ -0,0 +1,185 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public class AlgorithmParameterGenerator {
+
+    // Store spi service name
+    private static final String SERVICE = "AlgorithmParameterGenerator"; //$NON-NLS-1$
+
+    // Used to access common engine functionality
+    private static Engine engine = new Engine(SERVICE);
+
+    // Store SecureRandom
+    private static SecureRandom randm = new SecureRandom();
+
+    // Store used provider
+    private final Provider provider;
+
+    // Store used AlgorithmParameterGeneratorSpi implementation
+    private final AlgorithmParameterGeneratorSpi spiImpl;
+
+    //Store used algorithm
+    private final String algorithm;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected AlgorithmParameterGenerator(
+            AlgorithmParameterGeneratorSpi paramGenSpi, Provider provider,
+            String algorithm) {
+        this.provider = provider;
+        this.algorithm = algorithm;
+        this.spiImpl = paramGenSpi;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final String getAlgorithm() {
+        return algorithm;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     * throws NullPointerException when algorithm is null
+     */
+    public static AlgorithmParameterGenerator getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        if (algorithm == null) {
+            throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+        }
+        synchronized (engine) {
+            engine.getInstance(algorithm, null);
+            return new AlgorithmParameterGenerator(
+                    (AlgorithmParameterGeneratorSpi) engine.spi, engine.provider,
+                    algorithm);
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     * throws NullPointerException if algorithm is null (instead of
+     * NoSuchAlgorithmException) as in 1.4 release
+     */
+    public static AlgorithmParameterGenerator getInstance(String algorithm,
+            String provider) throws NoSuchAlgorithmException,
+            NoSuchProviderException {
+        if ((provider == null) || (provider.length() == 0)) {
+            throw new IllegalArgumentException(
+                    Messages.getString("security.02")); //$NON-NLS-1$
+        }
+        Provider impProvider = Security.getProvider(provider);
+        if (impProvider == null) {
+            throw new NoSuchProviderException(provider);
+        }
+        return getInstance(algorithm, impProvider);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     * throws NullPointerException if algorithm is null (instead of
+     * NoSuchAlgorithmException) as in 1.4 release
+     */
+    public static AlgorithmParameterGenerator getInstance(String algorithm,
+            Provider provider) throws NoSuchAlgorithmException {
+        if (provider == null) {
+            throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
+        }
+        if (algorithm == null) {
+            throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+        }
+        synchronized (engine) {
+            engine.getInstance(algorithm, provider, null);
+            return new AlgorithmParameterGenerator(
+                    (AlgorithmParameterGeneratorSpi) engine.spi, provider,
+                    algorithm);
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final Provider getProvider() {
+        return provider;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final void init(int size) {
+        spiImpl.engineInit(size, randm);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final void init(int size, SecureRandom random) {
+        spiImpl.engineInit(size, random);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final void init(AlgorithmParameterSpec genParamSpec)
+            throws InvalidAlgorithmParameterException {
+        spiImpl.engineInit(genParamSpec, randm);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final void init(AlgorithmParameterSpec genParamSpec,
+            SecureRandom random) throws InvalidAlgorithmParameterException {
+        spiImpl.engineInit(genParamSpec, random);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final AlgorithmParameters generateParameters() {
+        return spiImpl.engineGenerateParameters();
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/AlgorithmParameterGeneratorSpi.java b/libcore/security/src/main/java/java/security/AlgorithmParameterGeneratorSpi.java
new file mode 100644
index 0000000..70cb8d2
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/AlgorithmParameterGeneratorSpi.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public abstract class AlgorithmParameterGeneratorSpi {
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public AlgorithmParameterGeneratorSpi() {
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected abstract void engineInit(int size, SecureRandom random);
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected abstract void engineInit(AlgorithmParameterSpec genParamSpec,
+            SecureRandom random) throws InvalidAlgorithmParameterException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected abstract AlgorithmParameters engineGenerateParameters();
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/AlgorithmParameters.java b/libcore/security/src/main/java/java/security/AlgorithmParameters.java
new file mode 100644
index 0000000..e495439
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/AlgorithmParameters.java
@@ -0,0 +1,232 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris V. Kuznetsov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public class AlgorithmParameters {
+    /**
+     * The service name.
+     */
+    private static final String SEVICE = "AlgorithmParameters"; //$NON-NLS-1$
+
+    /**
+     * Used to access common engine functionality
+     */
+    private static Engine engine = new Engine(SEVICE);
+
+    /**
+     * The provider
+     */
+    private Provider provider;
+
+    /**
+     * The SPI implementation.
+     */
+    private AlgorithmParametersSpi spiImpl;
+
+    /**
+     * The algorithm.
+     */
+    private String algorithm;
+
+    /**
+     * The initialization state
+     */
+    private boolean initialized; // = false;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected AlgorithmParameters(AlgorithmParametersSpi keyFacSpi,
+            Provider provider, String algorithm) {
+        this.provider = provider;
+        this.algorithm = algorithm;
+        this.spiImpl = keyFacSpi;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public static AlgorithmParameters getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        if (algorithm == null) {
+            throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+        }
+        synchronized (engine) {       
+            engine.getInstance(algorithm, null);
+            return new AlgorithmParameters((AlgorithmParametersSpi) engine.spi,
+                    engine.provider, algorithm);
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public static AlgorithmParameters getInstance(String algorithm,
+            String provider) throws NoSuchAlgorithmException,
+            NoSuchProviderException {
+        if ((provider == null) || (provider.length() == 0)) {
+            throw new IllegalArgumentException(Messages.getString("security.02")); //$NON-NLS-1$
+        }
+        Provider p = Security.getProvider(provider);
+        if (p == null) {
+            throw new NoSuchProviderException(Messages.getString("security.03", //$NON-NLS-1$
+                    provider));
+        }
+        return getInstance(algorithm, p);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public static AlgorithmParameters getInstance(String algorithm,
+            Provider provider) throws NoSuchAlgorithmException {
+        if (provider == null) {
+            throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
+        }
+        if (algorithm == null) {
+            throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+        }
+        synchronized (engine) {
+            engine.getInstance(algorithm, provider, null);
+            return new AlgorithmParameters((AlgorithmParametersSpi) engine.spi,
+                    provider, algorithm);
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final Provider getProvider() {
+        return provider;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final String getAlgorithm() {
+        return algorithm;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final void init(AlgorithmParameterSpec paramSpec)
+            throws InvalidParameterSpecException {
+        if (initialized) {
+            throw new InvalidParameterSpecException(
+                    Messages.getString("security.1E")); //$NON-NLS-1$
+        }
+        spiImpl.engineInit(paramSpec);
+        initialized = true;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final void init(byte[] params) throws IOException {
+        if (initialized) {
+            throw new IOException(Messages.getString("security.1E")); //$NON-NLS-1$
+        }
+        spiImpl.engineInit(params);
+        initialized = true;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final void init(byte[] params, String format) throws IOException {
+        if (initialized) {
+            throw new IOException(Messages.getString("security.1E")); //$NON-NLS-1$
+        }
+        spiImpl.engineInit(params, format);
+        initialized = true;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final <T extends AlgorithmParameterSpec> T getParameterSpec(Class<T> paramSpec)
+            throws InvalidParameterSpecException {
+        if (!initialized) {
+            throw new InvalidParameterSpecException(
+                    Messages.getString("security.1F")); //$NON-NLS-1$
+        }
+        return spiImpl.engineGetParameterSpec(paramSpec);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final byte[] getEncoded() throws IOException {
+        if (!initialized) {
+            throw new IOException(Messages.getString("security.1F")); //$NON-NLS-1$
+        }
+        return spiImpl.engineGetEncoded();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final byte[] getEncoded(String format) throws IOException {
+        if (!initialized) {
+            throw new IOException(Messages.getString("security.1F")); //$NON-NLS-1$
+        }
+        return spiImpl.engineGetEncoded(format);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final String toString() {
+        if (!initialized) {
+            return null;
+        }
+        return spiImpl.engineToString();
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/AlgorithmParametersSpi.java b/libcore/security/src/main/java/java/security/AlgorithmParametersSpi.java
new file mode 100644
index 0000000..d405466
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/AlgorithmParametersSpi.java
@@ -0,0 +1,82 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris V. Kuznetsov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public abstract class AlgorithmParametersSpi {
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected abstract void engineInit(AlgorithmParameterSpec paramSpec)
+            throws InvalidParameterSpecException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected abstract void engineInit(byte[] params) throws IOException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected abstract void engineInit(byte[] params, String format)
+            throws IOException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected abstract <T extends AlgorithmParameterSpec> T engineGetParameterSpec(
+            Class<T> paramSpec) throws InvalidParameterSpecException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected abstract byte[] engineGetEncoded() throws IOException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected abstract byte[] engineGetEncoded(String format)
+            throws IOException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected abstract String engineToString();
+
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/AllPermission.java b/libcore/security/src/main/java/java/security/AllPermission.java
new file mode 100644
index 0000000..36a2087
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/AllPermission.java
@@ -0,0 +1,123 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package java.security;
+
+
+/**
+ * Subclass of Permission whose instances imply all other permissions. Granting
+ * this permission is equivalent to disabling security.
+ * 
+ */
+public final class AllPermission extends Permission {
+
+    /**
+     * @serial
+     */
+    private static final long serialVersionUID = -2916474571451318075L;
+
+    // Permission name
+    private static final String ALL_PERMISSIONS = "<all permissions>"; //$NON-NLS-1$
+
+    // Actions name
+    private static final String ALL_ACTIONS = "<all actions>"; //$NON-NLS-1$
+
+    /**
+     * Constructs a new instance of this class. The two argument version is
+     * provided for class <code>Policy</code> so that it has a consistent call
+     * pattern across all Permissions. The name and action list are both
+     * ignored.
+     * 
+     * @param name
+     *            java.lang.String ignored.
+     * @param actions
+     *            java.lang.String ignored.
+     */
+    public AllPermission(String name, String actions) {
+        super(ALL_PERMISSIONS);
+    }
+
+    /**
+     * Constructs a new instance of this class.
+     */
+    public AllPermission() {
+        super(ALL_PERMISSIONS);
+    }
+
+    /**
+     * Compares the argument to the receiver, and returns true if they represent
+     * the <em>same</em> object using a class specific comparison. All
+     * AllPermissions are equal to each other.
+     * 
+     * @param obj
+     *            the object to compare with this object
+     * @return <code>true</code> if the object is the same as this object
+     *         <code>false</code> if it is different from this object
+     * @see #hashCode
+     */
+    public boolean equals(Object obj) {
+        return (obj instanceof AllPermission);
+    }
+
+    /**
+     * Returns an integer hash code for the receiver. Any two objects which
+     * answer <code>true</code> when passed to <code>equals</code> must
+     * answer the same value for this method.
+     * 
+     * @return the receiver's hash
+     * 
+     * @see #equals
+     */
+    public int hashCode() {
+        return 1;
+    }
+
+    /**
+     * Returns the actions associated with the receiver. Since AllPermission
+     * objects allow all actions, answer with the string "<all actions>".
+     * 
+     * @return String the actions associated with the receiver.
+     */
+    public String getActions() {
+        return ALL_ACTIONS;
+    }
+
+    /**
+     * Indicates whether the argument permission is implied by the receiver.
+     * AllPermission objects imply all other permissions.
+     * 
+     * @return boolean <code>true</code> if the argument permission is implied
+     *         by the receiver, and <code>false</code> if it is not.
+     * @param permission
+     *            java.security.Permission the permission to check
+     */
+    public boolean implies(Permission permission) {
+        return true;
+    }
+
+    /**
+     * Returns a new PermissionCollection for holding permissions of this class.
+     * Answer null if any permission collection can be used.
+     * 
+     * @return a new PermissionCollection or null
+     * 
+     * @see java.security.BasicPermissionCollection
+     */
+    public PermissionCollection newPermissionCollection() {
+        return new AllPermissionCollection();
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/AllPermissionCollection.java b/libcore/security/src/main/java/java/security/AllPermissionCollection.java
new file mode 100644
index 0000000..08b0b1e
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/AllPermissionCollection.java
@@ -0,0 +1,140 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package java.security;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * Specific PermissionCollection for storing AllPermissions. All instances of
+ * AllPermission are equivalent, so it is enough to store a single added
+ * instance.
+ * 
+ */
+final class AllPermissionCollection extends PermissionCollection {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = -4023755556366636806L;
+
+    private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField(
+        "all_allowed", Boolean.TYPE), }; //$NON-NLS-1$
+
+    // Single element of collection.
+    private transient Permission all;
+
+    /**
+     * Adds an AllPermission to the collection.
+     */
+    public void add(Permission permission) {
+        if (isReadOnly()) {
+            throw new SecurityException(Messages.getString("security.15")); //$NON-NLS-1$
+        }
+        if (!(permission instanceof AllPermission)) {
+            throw new IllegalArgumentException(Messages.getString("security.16", //$NON-NLS-1$
+                permission));
+        }
+        all = permission;
+    }
+
+    /**
+     * Returns enumeration of the collection.
+     */
+    public Enumeration<Permission> elements() {
+        return new SingletonEnumeration<Permission>(all);
+    }
+
+    /**
+     * An auxiliary implementation for enumerating a single object.
+     * 
+     */
+    final static class SingletonEnumeration<E> implements Enumeration<E> {
+
+        private E element;
+
+        /**
+         * Constructor taking the single element.
+         */
+        public SingletonEnumeration(E single) {
+            element = single;
+        }
+
+        /**
+         * Returns true if the element is not enumerated yet.
+         */
+        public boolean hasMoreElements() {
+            return element != null;
+        }
+
+        /**
+         * Returns the element and clears internal reference to it.
+         */
+        public E nextElement() {
+            if (element == null) {
+                throw new NoSuchElementException(Messages.getString("security.17")); //$NON-NLS-1$
+            }
+            E last = element;
+            element = null;
+            return last;
+        }
+    }
+
+    /**
+     * Indicates whether the argument permission is implied by the receiver.
+     * AllPermission objects imply all other permissions.
+     * 
+     * @return boolean <code>true</code> if the argument permission is implied
+     *         by the receiver, and <code>false</code> if it is not.
+     * @param permission
+     *            java.security.Permission the permission to check
+     */
+    public boolean implies(Permission permission) {
+        return all != null;
+    }
+
+    /**
+     * Writes accordingly to expected format:
+     * <dl>
+     * <dt>boolean all_allowed
+     * <dd>This is set to true if this collection is not empty
+     * </dl>
+     */
+    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
+        ObjectOutputStream.PutField fields = out.putFields();
+        fields.put("all_allowed", all != null); //$NON-NLS-1$
+        out.writeFields();
+    }
+
+    /**
+     * Restores internal state.
+     */
+    private void readObject(java.io.ObjectInputStream in) throws IOException,
+        ClassNotFoundException {
+        ObjectInputStream.GetField fields = in.readFields();
+        if (fields.get("all_allowed", false)) { //$NON-NLS-1$
+            all = new AllPermission();
+        }
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/AuthProvider.java b/libcore/security/src/main/java/java/security/AuthProvider.java
new file mode 100644
index 0000000..ae8b159
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/AuthProvider.java
@@ -0,0 +1,66 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris V. Kuznetsov
+* @version $Revision$
+*/
+
+package java.security;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginException;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public abstract class AuthProvider extends Provider {
+
+    /**
+     * @serial
+     */
+    private static final long serialVersionUID = 4197859053084546461L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    protected AuthProvider(String name, double version, String info) {
+        super(name, version, info); 
+    }
+    
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    public abstract void login(Subject subject, CallbackHandler handler) throws LoginException;
+    
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    public abstract void logout() throws LoginException;
+    
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    public abstract void setCallbackHandler(CallbackHandler handler);
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/BasicPermission.java b/libcore/security/src/main/java/java/security/BasicPermission.java
new file mode 100644
index 0000000..9cda9a2
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/BasicPermission.java
@@ -0,0 +1,193 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * Superclass of permissions which have names but no action lists.
+ * 
+ */
+
+public abstract class BasicPermission extends Permission implements
+    Serializable {
+
+    private static final long serialVersionUID = 6279438298436773498L;
+
+    /**
+     * Creates an instance of this class with the given name and action list.
+     * 
+     * @param name
+     *            String the name of the new permission.
+     */
+    public BasicPermission(String name) {
+        super(name);
+        checkName(name);
+    }
+
+    /**
+     * Creates an instance of this class with the given name and action list.
+     * The action list is ignored.
+     * 
+     * @param name
+     *            String the name of the new permission.
+     * @param action
+     *            String ignored.
+     */
+    public BasicPermission(String name, String action) {
+        super(name);
+        checkName(name);
+    }
+
+    /**
+     * Checks name parameter
+     */ 
+    private final void checkName(String name) {
+        if (name == null) {
+            throw new NullPointerException(Messages.getString("security.28")); //$NON-NLS-1$
+        }
+        if (name.length() == 0) {
+            throw new IllegalArgumentException(Messages.getString("security.29")); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Compares the argument to the receiver, and returns true if they represent
+     * the <em>same</em> object using a class specific comparison. In this
+     * case, the receiver and the object must have the same class and name.
+     * 
+     * @param obj
+     *            the object to compare with this object
+     * @return <code>true</code> if the object is the same as this object
+     *         <code>false</code> if it is different from this object
+     * @see #hashCode
+     */
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+
+        if (obj != null && obj.getClass() == this.getClass()) {
+            return this.getName().equals(((Permission)obj).getName());
+        }
+        return false;
+    }
+
+    /**
+     * Returns an integer hash code for the receiver. Any two objects which
+     * answer <code>true</code> when passed to <code>equals</code> must
+     * answer the same value for this method.
+     * 
+     * @return int the receiver's hash
+     * 
+     * @see #equals
+     */
+    public int hashCode() {
+        return getName().hashCode();
+    }
+
+    /**
+     * Returns the actions associated with the receiver. BasicPermission objects
+     * have no actions, so answer the empty string.
+     * 
+     * @return String the actions associated with the receiver.
+     */
+    public String getActions() {
+        return ""; //$NON-NLS-1$
+    }
+
+    /**
+     * Indicates whether the argument permission is implied by the receiver.
+     * 
+     * @return boolean <code>true</code> if the argument permission is implied
+     *         by the receiver, and <code>false</code> if it is not.
+     * @param permission
+     *            java.security.Permission the permission to check
+     */
+    public boolean implies(Permission permission) {
+        if (permission != null && permission.getClass() == this.getClass()) {
+            return nameImplies(getName(), permission.getName());
+        }
+        return false;
+    }
+
+    /**
+     * Checks if <code>thisName</code> implies <code>thatName</code>,
+     * accordingly to hierarchical property naming convention.
+     * It is assumed that names cannot be null or empty.
+     */
+    static boolean nameImplies(String thisName, String thatName) {
+        if (thisName == thatName) {
+            return true;
+        }
+        int end = thisName.length();
+        if (end > thatName.length()) {
+            return false;
+        }
+        if (thisName.charAt(--end) == '*'
+            && (end == 0 || thisName.charAt(end - 1) == '.')) {
+            //wildcard found
+            end--;
+        } else if (end != (thatName.length()-1)) {
+            //names are not equal
+            return false;
+        }
+        for (int i = end; i >= 0; i--) {
+            if (thisName.charAt(i) != thatName.charAt(i)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Returns a new PermissionCollection for holding permissions of this class.
+     * Answer null if any permission collection can be used.
+     * <p>
+     * Note: For BasicPermission (and subclasses which do not override this
+     * method), the collection which is returned does <em>not</em> invoke the
+     * .implies method of the permissions which are stored in it when checking
+     * if the collection implies a permission. Instead, it assumes that if the
+     * type of the permission is correct, and the name of the permission is
+     * correct, there is a match.
+     * 
+     * @return a new PermissionCollection or null
+     * 
+     * @see java.security.BasicPermissionCollection
+     */
+    public PermissionCollection newPermissionCollection() {
+        return new BasicPermissionCollection();
+    }
+
+    /**
+     * Checks name after default deserialization.
+     */
+    private void readObject(java.io.ObjectInputStream in) throws IOException,
+        ClassNotFoundException {
+        in.defaultReadObject();
+        checkName(this.getName());
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/BasicPermissionCollection.java b/libcore/security/src/main/java/java/security/BasicPermissionCollection.java
new file mode 100644
index 0000000..46dad02
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/BasicPermissionCollection.java
@@ -0,0 +1,196 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package java.security;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * Specific PermissionCollection for storing BasicPermissions of arbitrary type.
+ * 
+ */
+
+final class BasicPermissionCollection extends PermissionCollection {
+
+    private static final long serialVersionUID = 739301742472979399L;
+
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("all_allowed", Boolean.TYPE), //$NON-NLS-1$
+        new ObjectStreamField("permissions", Hashtable.class), //$NON-NLS-1$
+        new ObjectStreamField("permClass", Class.class), }; //$NON-NLS-1$
+
+    //should be final, but because of writeObject() cannot be
+    private transient Map<String, Permission> items = new HashMap<String, Permission>();
+
+    // true if this Collection contains a BasicPermission with '*' as its permission name
+    private transient boolean allEnabled; // = false;
+
+    private Class<? extends Permission> permClass;
+
+    /**
+     * Adds a permission to the collection. The first added permission must be a
+     * subclass of BasicPermission, next permissions must be of the same class
+     * as the first one.
+     * 
+     * @see java.security.PermissionCollection#add(java.security.Permission)
+     */
+    public void add(Permission permission) {
+        if (isReadOnly()) {
+            throw new SecurityException(Messages.getString("security.15")); //$NON-NLS-1$
+        }
+        if (permission == null) {
+            throw new IllegalArgumentException(Messages.getString("security.20")); //$NON-NLS-1$
+        }
+
+        Class<? extends Permission> inClass = permission.getClass();
+        if (permClass != null) {
+            if (permClass != inClass) {
+                throw new IllegalArgumentException(Messages.getString("security.16", //$NON-NLS-1$
+                    permission));
+            }
+        } else if( !(permission instanceof BasicPermission)) {
+            throw new IllegalArgumentException(Messages.getString("security.16", //$NON-NLS-1$
+                permission));
+        } else { 
+            // this is the first element provided that another thread did not add
+            synchronized (items) {
+                if (permClass != null && inClass != permClass) {
+                    throw new IllegalArgumentException(Messages.getString("security.16", //$NON-NLS-1$
+                        permission));
+                }
+                permClass = inClass;
+            }
+        }
+
+        String name = permission.getName();
+        items.put(name, permission);
+        allEnabled = allEnabled || (name.length() == 1 && '*' == name.charAt(0));
+    }
+
+    /**
+     * Returns enumeration of contained elements.
+     */
+    public Enumeration<Permission> elements() {
+        return Collections.enumeration(items.values());
+    }
+
+    /**
+     * Indicates whether the argument permission is implied by the receiver.
+     * 
+     * @return boolean <code>true</code> if the argument permission is implied
+     *         by the receiver, and <code>false</code> if it is not.
+     * @param permission
+     *            java.security.Permission the permission to check
+     */
+    public boolean implies(Permission permission) {
+        if (permission == null || permission.getClass() != permClass) {
+            return false;
+        }
+        if (allEnabled) {
+            return true;
+        }
+        String checkName = permission.getName();
+        //first check direct coincidence
+        if (items.containsKey(checkName)) {
+            return true;
+        }
+        //now check if there are suitable wildcards
+        //suppose we have "a.b.c", let's check "a.b.*" and "a.*" 
+        char[] name = checkName.toCharArray();
+        //I presume that "a.b.*" does not imply "a.b." 
+        //so the dot at end is ignored 
+        int pos = name.length - 2; 
+        for (; pos >= 0; pos--) {
+            if (name[pos] == '.') {
+                break;
+            }
+        }
+        while (pos >= 0) {
+            name[pos + 1] = '*'; 
+            if (items.containsKey(new String(name, 0, pos + 2))) {
+                return true;
+            }
+            for (--pos; pos >= 0; pos--) {
+                if (name[pos] == '.') {
+                    break;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Expected format is the following:
+     * <dl>
+     * <dt>boolean all_allowed
+     * <dd>This is set to true if this BasicPermissionCollection contains a
+     * BasicPermission with '*' as its permission name.
+     * <dt>Class&lt;T&gt; permClass
+     * <dd>The class to which all BasicPermissions in this
+     * BasicPermissionCollection belongs.
+     * <dt>Hashtable&lt;K,V&gt; permissions
+     * <dd>The BasicPermissions in this BasicPermissionCollection. All
+     * BasicPermissions in the collection must belong to the same class. The
+     * Hashtable is indexed by the BasicPermission name; the value of the
+     * Hashtable entry is the permission.
+     * </dl>
+     */
+    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
+        ObjectOutputStream.PutField fields = out.putFields();
+        fields.put("all_allowed", allEnabled); //$NON-NLS-1$
+        fields.put("permissions", new Hashtable<String, Permission>(items)); //$NON-NLS-1$
+        fields.put("permClass", permClass); //$NON-NLS-1$
+        out.writeFields();
+    }
+
+    /**
+     * Reads the object from stream and checks its consistency: all contained
+     * permissions must be of the same subclass of BasicPermission.
+     */
+    private void readObject(java.io.ObjectInputStream in) throws IOException,
+        ClassNotFoundException {
+        ObjectInputStream.GetField fields = in.readFields();
+
+        items = new HashMap<String, Permission>();
+        synchronized (items) {
+            permClass = (Class<? extends Permission>)fields.get("permClass", null); //$NON-NLS-1$
+            items.putAll((Hashtable<String, Permission>) fields.get(
+                    "permissions", new Hashtable<String, Permission>())); //$NON-NLS-1$
+            for (Iterator<Permission> iter = items.values().iterator(); iter.hasNext();) {
+                if (iter.next().getClass() != permClass) {
+                    throw new InvalidObjectException(Messages.getString("security.24")); //$NON-NLS-1$
+                }
+            }
+            allEnabled = fields.get("all_allowed", false); //$NON-NLS-1$
+            if (allEnabled && !items.containsKey("*")) { //$NON-NLS-1$
+                throw new InvalidObjectException(Messages.getString("security.25")); //$NON-NLS-1$
+            }
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/Certificate.java b/libcore/security/src/main/java/java/security/Certificate.java
new file mode 100644
index 0000000..22beac0
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/Certificate.java
@@ -0,0 +1,76 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ * @deprecated Replaced by behavior in
+ *             {@link javax.security.cert javax.security.cert}
+ */
+public interface Certificate {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void decode(InputStream stream) throws KeyException, IOException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void encode(OutputStream stream) throws KeyException, IOException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public String getFormat();
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public Principal getGuarantor();
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public Principal getPrincipal();
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public PublicKey getPublicKey();
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public String toString(boolean detailed);
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/CodeSigner.java b/libcore/security/src/main/java/java/security/CodeSigner.java
new file mode 100644
index 0000000..710e4f8
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/CodeSigner.java
@@ -0,0 +1,124 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Astapchuk
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.Serializable;
+import java.security.cert.CertPath;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref 
+ */
+
+public final class CodeSigner implements Serializable {
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    private static final long serialVersionUID = 6819288105193937581L;
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    private CertPath signerCertPath;
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    private Timestamp timestamp;
+
+    // Cached hash code value
+    private transient int hash;
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public CodeSigner(CertPath signerCertPath, Timestamp timestamp) {
+        if (signerCertPath == null) {
+            throw new NullPointerException(Messages.getString("security.10")); //$NON-NLS-1$
+        }
+        this.signerCertPath = signerCertPath;
+        this.timestamp = timestamp;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj instanceof CodeSigner) {
+            CodeSigner that = (CodeSigner) obj;
+            if (!signerCertPath.equals(that.signerCertPath)) {
+                return false;
+            }
+            return timestamp == null ? that.timestamp == null : timestamp
+                    .equals(that.timestamp);
+        }
+        return false;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public CertPath getSignerCertPath() {
+        return signerCertPath;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public Timestamp getTimestamp() {
+        return timestamp;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public int hashCode() {
+        if (hash == 0) {
+            hash = signerCertPath.hashCode()
+                    ^ (timestamp == null ? 0 : timestamp.hashCode());
+        }
+        return hash;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public String toString() {
+        // There is no any special reason for '256' here, it's taken abruptly
+        // FIXME: 1.5 StringBuffer => StringBuilder
+        StringBuffer buf = new StringBuffer(256);
+        // The javadoc says nothing, and the others implementations behavior seems as 
+        // dumping only the first certificate. Well, let's do the same.
+        buf.append("CodeSigner [").append(signerCertPath.getCertificates().get(0)); //$NON-NLS-1$
+        if( timestamp != null ) {
+            buf.append("; ").append(timestamp); //$NON-NLS-1$
+        }
+        buf.append("]"); //$NON-NLS-1$
+        return buf.toString();
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/CodeSource.java b/libcore/security/src/main/java/java/security/CodeSource.java
new file mode 100644
index 0000000..8c235e6
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/CodeSource.java
@@ -0,0 +1,547 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Astapchuk
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.OptionalDataException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.net.SocketPermission;
+import java.net.URL;
+import java.security.cert.CertPath;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.fortress.PolicyUtils;
+import org.apache.harmony.security.internal.nls.Messages;
+
+public class CodeSource implements Serializable {
+
+    private static final long serialVersionUID = 4977541819976013951L;
+
+    // Location of this CodeSource object
+    private URL location;
+
+    // Array of certificates assigned to this CodeSource object
+    private transient java.security.cert.Certificate[] certs;
+
+    // Array of CodeSigners
+    private transient CodeSigner[] signers;
+
+    // SocketPermission() in implies() method takes to many time.
+    // Need to cache it for better performance.
+    private transient SocketPermission sp;
+
+    // Cached factory used to build CertPath-s in <code>getCodeSigners()</code>.  
+    private transient CertificateFactory factory;
+
+    /**
+     * Constructs a new instance of this class with its url and certificates
+     * fields filled in from the arguments.
+     * 
+     * @param location
+     *            URL the URL.
+     * @param certs
+     *            Certificate[] the Certificates.
+     */
+    public CodeSource(URL location, Certificate[] certs) {
+        this.location = location;
+        if (certs != null) {
+            this.certs = new Certificate[certs.length];
+            System.arraycopy(certs, 0, this.certs, 0, certs.length);
+        }
+    }
+
+    public CodeSource(URL location, CodeSigner[] signers) {
+        this.location = location;
+        if (signers != null) {
+            this.signers = new CodeSigner[signers.length];
+            System.arraycopy(signers, 0, this.signers, 0, signers.length);
+        }
+    }
+
+    /**
+     * Compares the argument to the receiver, and returns true if they represent
+     * the <em>same</em> object using a class specific comparison. In this
+     * case, the receiver and the object must have the same URL and the same
+     * collection of certificates.
+     * 
+     * 
+     * @param obj
+     *            the object to compare with this object
+     * @return <code>true</code> if the object is the same as this object
+     *         <code>false</code> if it is different from this object
+     * @see #hashCode
+     */
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+
+        if (!(obj instanceof CodeSource)) {
+            return false;
+        }
+
+        CodeSource that = (CodeSource) obj;
+
+        if (this.location != null) {
+            if (that.location == null) {
+                return false;
+            }
+            if (!this.location.equals(that.location)) {
+                return false;
+            }
+        } else if (that.location != null) {
+            return false;
+        }
+
+        // do not use this.certs, as we also need to take care about 
+        // CodeSigners' certificates
+        Certificate[] thizCerts = getCertificatesNoClone();
+        Certificate[] thatCerts = that.getCertificatesNoClone();
+        if (!PolicyUtils.matchSubset(thizCerts, thatCerts)) {
+            return false;
+        }
+        if (!PolicyUtils.matchSubset(thatCerts, thizCerts)) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Returns the certificates held onto by the receiver.
+     * 
+     * 
+     * @return Certificate[] the receiver's certificates
+     */
+    public final Certificate[] getCertificates() {
+        getCertificatesNoClone();
+        if (certs == null) {
+            return null;
+        }
+        Certificate[] tmp = new Certificate[certs.length];
+        System.arraycopy(certs, 0, tmp, 0, certs.length);
+        return tmp;
+    }
+
+    // Acts exactly as {@link #getCertificates()} does, but does not clone the 
+    // array before returning (and returns reference to <code>this.certs</code>
+    // if this array is not null).<br>
+    // @return a reference to the certificates array, or null if there are no 
+    // certificates associated.  
+    private Certificate[] getCertificatesNoClone() {
+        if (certs != null) {
+            return certs;
+        }
+
+        if (signers == null) {
+            return null;
+        }
+        // Extract Certificates from the CodeSigner-s
+        ArrayList<Certificate> v = new ArrayList<Certificate>();
+        for (int i = 0; i < signers.length; i++) {
+            v.addAll(signers[i].getSignerCertPath().getCertificates());
+        }
+
+        certs = v.toArray(new Certificate[v.size()]);
+        return certs;
+    }
+
+    public final CodeSigner[] getCodeSigners() {
+        if (signers != null) {
+            CodeSigner[] tmp = new CodeSigner[signers.length];
+            System.arraycopy(signers, 0, tmp, 0, tmp.length);
+            return tmp;
+        }
+        if(certs == null || factory != null){
+            // factory != null means we've done this exercise already.
+            return null;
+        }
+
+        X500Principal prevIssuer = null;
+        ArrayList<Certificate> list = new ArrayList<Certificate>(certs.length);
+        ArrayList<CodeSigner> asigners = new ArrayList<CodeSigner>();
+
+        // The presumption is that the chains of certificates are placed
+        // according to the CertPath agreement:
+        //
+        // the lowest certs first; the CAs are at the last
+        //
+        // So the following loop scans trough the certs and checks
+        // that every next certificate is an Issuer of the previous one. 
+        // Any certificate that is not an Issuer of the previous one starts a 
+        // new chain (== a new CertPath) 
+
+        for (int i = 0; i < certs.length; i++) {
+            if (!(certs[i] instanceof X509Certificate)) {
+                // Only X509Certificate-s are taken into account - see API spec.
+                continue;
+            }
+            X509Certificate x509 = (X509Certificate) certs[i];
+            if (prevIssuer == null) {
+                // start a very first chain
+                prevIssuer = x509.getIssuerX500Principal();
+                list.add(x509);
+            } else {
+                X500Principal subj = x509.getSubjectX500Principal();
+                if (!prevIssuer.equals(subj)) {
+                    // Ok, this ends the previous chain, 
+                    // so transform this one into CertPath ...
+                    CertPath cpath = makeCertPath(list);
+                    if (cpath != null) {
+                        asigners.add(new CodeSigner(cpath, null));
+                    }
+                    // ... and start a new one
+                    list.clear();
+                }// else { it's still the same chain }
+                prevIssuer = x509.getSubjectX500Principal();
+                list.add(x509);
+            }
+        }
+        if (!list.isEmpty()) {
+            CertPath cpath = makeCertPath(list);
+            if (cpath != null) {
+                asigners.add(new CodeSigner(cpath, null));
+            }
+        }
+        if (asigners.isEmpty()) {
+            // 'signers' is 'null' already
+            return null;
+        }
+        signers = new CodeSigner[asigners.size()];
+        asigners.toArray(signers);
+        CodeSigner[] tmp = new CodeSigner[asigners.size()];
+        System.arraycopy(signers, 0, tmp, 0, tmp.length);
+        return tmp;
+    }
+
+    // Makes an CertPath from a given List of X509Certificate-s. 
+    // @param list
+    // @return CertPath, or null if CertPath cannot be made  
+    private CertPath makeCertPath(List<? extends Certificate> list) {
+        if (factory == null) {
+            try {
+                factory = CertificateFactory.getInstance("X.509"); //$NON-NLS-1$
+            } catch (CertificateException ex) {
+                //? throw new Error("X.509 is a 'must be'", ex);
+                return null;
+            }
+        }
+        try {
+            return factory.generateCertPath(list);
+        } catch (CertificateException ex) {
+            // ignore(ex)
+        }
+        return null;
+    }
+
+    /**
+     * Returns the receiver's location.
+     * 
+     * 
+     * @return URL the receiver's URL
+     */
+    public final URL getLocation() {
+        return location;
+    }
+
+    /**
+     * Returns an integer hash code for the receiver. Any two objects which
+     * answer <code>true</code> when passed to <code>.equals</code> must
+     * answer the same value for this method.
+     * 
+     * 
+     * @return int the receiver's hash.
+     * 
+     * @see #equals
+     */
+    public int hashCode() {
+        //
+        // hashCode() is undocumented there. Should we also use certs[i] to
+        // compute the hash ?
+        // for now, I don't take certs[] into account
+        return location == null ? 0 : location.hashCode();
+    }
+
+    /**
+     * Indicates whether the argument code source is implied by the receiver.
+     * 
+     * 
+     * @return boolean <code>true</code> if the argument code source is
+     *         implied by the receiver, and <code>false</code> if it is not.
+     * @param cs
+     *            CodeSource the code source to check
+     */
+    public boolean implies(CodeSource cs) {
+        //
+        // Here, javadoc:N refers to the appropriate item in the API spec for 
+        // the CodeSource.implies()
+        // The info was taken from the 1.5 final API spec
+
+        // javadoc:1
+        if (cs == null) {
+            return false;
+        }
+
+        // javadoc:2
+        // with a comment: the javadoc says only about certificates and does 
+        // not explicitly mention CodeSigners' certs.
+        // It seems more convenient to use getCerts() to get the real 
+        // certificates - with a certificates got form the signers
+        Certificate[] thizCerts = getCertificatesNoClone();
+        if (thizCerts != null) {
+            Certificate[] thatCerts = cs.getCertificatesNoClone();
+            if (thatCerts == null
+                    || !PolicyUtils.matchSubset(thizCerts, thatCerts)) {
+                return false;
+            }
+        }
+
+        // javadoc:3
+        if (this.location != null) {
+            //javadoc:3.1
+            if (cs.location == null) {
+                return false;
+            }
+            //javadoc:3.2
+            if (this.location.equals(cs.location)) {
+                return true;
+            }
+            //javadoc:3.3
+            if (!this.location.getProtocol().equals(cs.location.getProtocol())) {
+                return false;
+            }
+            //javadoc:3.4
+            String thisHost = this.location.getHost();
+            if (thisHost != null) {
+                String thatHost = cs.location.getHost();
+                if (thatHost == null) {
+                    return false;
+                }
+
+                // 1. According to the spec, an empty string will be considered 
+                // as "localhost" in the SocketPermission
+                // 2. 'file://' URLs will have an empty getHost()
+                // so, let's make a special processing of localhost-s, I do 
+                // believe this'll improve performance of file:// code sources 
+
+                //
+                // Don't have to evaluate both the boolean-s each time.
+                // It's better to evaluate them directly under if() statement.
+                // 
+                // boolean thisIsLocalHost = thisHost.length() == 0 || "localhost".equals(thisHost);
+                // boolean thatIsLocalHost = thatHost.length() == 0 || "localhost".equals(thatHost);
+                // 
+                // if( !(thisIsLocalHost && thatIsLocalHost) &&
+                // !thisHost.equals(thatHost)) {
+
+                if (!((thisHost.length() == 0 || "localhost".equals(thisHost)) && (thatHost //$NON-NLS-1$
+                        .length() == 0 || "localhost".equals(thatHost))) //$NON-NLS-1$
+                        && !thisHost.equals(thatHost)) {
+
+                    // Obvious, but very slow way....
+                    // 
+                    // SocketPermission thisPerm = new SocketPermission(
+                    //          this.location.getHost(), "resolve");
+                    // SocketPermission thatPerm = new SocketPermission(
+                    //          cs.location.getHost(), "resolve");
+                    // if (!thisPerm.implies(thatPerm)) { 
+                    //      return false;
+                    // }
+                    //
+                    // let's cache it: 
+
+                    if (this.sp == null) {
+                        this.sp = new SocketPermission(thisHost, "resolve"); //$NON-NLS-1$
+                    }
+
+                    if (cs.sp == null) {
+                        cs.sp = new SocketPermission(thatHost, "resolve"); //$NON-NLS-1$
+                    }
+
+                    if (!this.sp.implies(cs.sp)) {
+                        return false;
+                    }
+                } // if( ! this.location.getHost().equals(cs.location.getHost())
+            } // if (this.location.getHost() != null)
+
+            //javadoc:3.5
+            if (this.location.getPort() != -1) {
+                if (this.location.getPort() != cs.location.getPort()) {
+                    return false;
+                }
+            }
+
+            //javadoc:3.6
+            String thisFile = this.location.getFile();
+            String thatFile = cs.location.getFile();
+
+            if (thisFile.endsWith("/-")) { //javadoc:3.6."/-" //$NON-NLS-1$
+                if (!thatFile.startsWith(thisFile.substring(0, thisFile
+                        .length() - 2))) {
+                    return false;
+                }
+            } else if (thisFile.endsWith("/*")) { //javadoc:3.6."/*" //$NON-NLS-1$
+                if (!thatFile.startsWith(thisFile.substring(0, thisFile
+                        .length() - 2))) {
+                    return false;
+                }
+                // no further separators(s) allowed
+                if (thatFile.indexOf("/", thisFile.length() - 1) != -1) { //$NON-NLS-1$
+                    return false;
+                }
+            } else {
+                // javadoc:3.6."/"
+                if (!thisFile.equals(thatFile)) {
+                    if (!thisFile.endsWith("/")) { //$NON-NLS-1$
+                        if (!thatFile.equals(thisFile + "/")) { //$NON-NLS-1$
+                            return false;
+                        }
+                    } else {
+                        return false;
+                    }
+                }
+            }
+
+            //javadoc:3.7
+            if (this.location.getRef() != null) {
+                if (!this.location.getRef().equals(cs.location.getRef())) {
+                    return false;
+                }
+            }
+            // ok, every check was made, and they all were successful. 
+            // it's ok to return true.
+        } // if this.location != null
+
+        // javadoc: a note about CodeSource with null location and null Certs 
+        // is applicable here 
+        return true;
+    }
+
+    /**
+     * Returns a string containing a concise, human-readable description of the
+     * receiver.
+     * 
+     * 
+     * @return a printable representation for the receiver.
+     */
+    public String toString() {
+        StringBuilder buf = new StringBuilder();
+        buf.append("CodeSource, url="); //$NON-NLS-1$
+        buf.append(location == null ? "<null>" : location.toString()); //$NON-NLS-1$
+
+        if (certs == null) {
+            buf.append(", <no certificates>"); //$NON-NLS-1$
+        } else {
+            buf.append("\nCertificates [\n"); //$NON-NLS-1$
+            for (int i = 0; i < certs.length; i++) {
+                buf.append(i + 1).append(") ").append(certs[i]).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$
+            }
+            buf.append("]\n"); //$NON-NLS-1$
+        }
+        if (signers != null) {
+            buf.append("\nCodeSigners [\n"); //$NON-NLS-1$
+            for (int i = 0; i < signers.length; i++) {
+                buf.append(i + 1).append(") ").append(signers[i]).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$
+            }
+            buf.append("]\n"); //$NON-NLS-1$
+        }
+        return buf.toString();
+    }
+
+    private void writeObject(ObjectOutputStream oos) throws IOException {
+
+        oos.defaultWriteObject();
+
+        if (certs == null || certs.length == 0) {
+            oos.writeInt(0);
+        } else {
+            oos.writeInt(certs.length);
+            for (int i = 0; i < certs.length; i++) {
+                try {
+                    oos.writeUTF(certs[i].getType());
+                    byte[] data = certs[i].getEncoded();
+                    // hope there are no certificates with 'data==null'
+                    oos.writeInt(data.length);
+                    oos.write(data);
+                } catch (CertificateEncodingException ex) {
+                    throw (IOException) new IOException(
+                            Messages.getString("security.18")).initCause(ex); //$NON-NLS-1$
+                }
+            }
+        }
+        if (signers != null && signers.length != 0) {
+            oos.writeObject(signers);
+        }
+    }
+
+    private void readObject(ObjectInputStream ois) throws IOException,
+            ClassNotFoundException {
+        
+        ois.defaultReadObject();
+        
+        int certsCount = ois.readInt();
+        certs = null;
+        if (certsCount != 0) {
+            certs = new Certificate[certsCount];
+            for (int i = 0; i < certsCount; i++) {
+                String type = ois.readUTF();
+                CertificateFactory factory;
+                try {
+                    factory = CertificateFactory.getInstance(type);
+                } catch (CertificateException ex) {
+                    throw new ClassNotFoundException(
+                            Messages.getString("security.19", type), //$NON-NLS-1$
+                            ex);
+                }
+                int dataLen = ois.readInt();
+                byte[] data = new byte[dataLen];
+                ois.readFully(data);
+                ByteArrayInputStream bais = new ByteArrayInputStream(data);
+                try {
+                    certs[i] = factory.generateCertificate(bais);
+                } catch (CertificateException ex) {
+                    throw (IOException) new IOException(
+                            Messages.getString("security.1A")).initCause(ex); //$NON-NLS-1$
+                }
+            }
+        }
+        try {
+            signers = (CodeSigner[]) ois.readObject();
+        } catch (OptionalDataException ex) {
+            if (!ex.eof) {
+                throw ex;
+            }
+            // no signers (ex.eof==true <= no data left) is allowed
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/DigestException.java b/libcore/security/src/main/java/java/security/DigestException.java
new file mode 100644
index 0000000..b63edda
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/DigestException.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * This class represents exceptions for message digest computation.
+ * 
+ */
+public class DigestException extends GeneralSecurityException {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = 5821450303093652515L;
+
+    /**
+     * Constructs a new instance of this class with its walkback and message
+     * filled in.
+     * 
+     * 
+     * @param msg
+     *            String The detail message for the exception.
+     */
+    public DigestException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a new instance of this class with its walkback filled in.
+     * 
+     */
+    public DigestException() {
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public DigestException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public DigestException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/DigestInputStream.java b/libcore/security/src/main/java/java/security/DigestInputStream.java
new file mode 100644
index 0000000..84ce3ad
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/DigestInputStream.java
@@ -0,0 +1,143 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class DigestInputStream extends FilterInputStream {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    protected MessageDigest digest;
+
+    // Indicates whether digest functionality is on or off
+    private boolean isOn = true;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public DigestInputStream(InputStream stream, MessageDigest digest) {
+        super(stream);
+        this.digest = digest;
+    }
+
+    /**
+     * Returns the MessageDigest which the receiver uses when computing the
+     * hash.
+     * 
+     * 
+     * @return MessageDigest the digest the receiver uses when computing the
+     *         hash.
+     * 
+     */
+    public MessageDigest getMessageDigest() {
+        return digest;
+    }
+
+    /**
+     * Sets the MessageDigest which the receiver will use when computing the
+     * hash.
+     * 
+     * 
+     * @param digest
+     *            MessageDigest the digest to use when computing the hash.
+     * 
+     * @see MessageDigest
+     * @see #on
+     */
+    public void setMessageDigest(MessageDigest digest) {
+        this.digest = digest;
+    }
+
+    /**
+     * Reads the next byte and returns it as an int. Updates the digest for the
+     * byte if this function is enabled.
+     * 
+     * 
+     * @return int the byte which was read or -1 at end of stream.
+     * 
+     * @exception java.io.IOException
+     *                If reading the source stream causes an IOException.
+     */
+    public int read() throws IOException {
+        // read the next byte
+        int byteRead = in.read();
+        // update digest only if
+        // - digest functionality is on
+        // - eos has not been reached
+        if (isOn && (byteRead != -1)) {
+            digest.update((byte)byteRead);
+        }
+        // return byte read
+        return byteRead;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public int read(byte[] b, int off, int len) throws IOException {
+        // read next up to len bytes
+        int bytesRead = in.read(b, off, len);
+        // update digest only if
+        // - digest functionality is on
+        // - eos has not been reached
+        if (isOn && (bytesRead != -1)) {
+            digest.update(b, off, bytesRead);
+        }
+        // return number of bytes read
+        return bytesRead;
+    }
+
+    /**
+     * Enables or disables the digest function (default is on).
+     * 
+     * 
+     * @param on
+     *            boolean true if the digest should be computed, and false
+     *            otherwise.
+     * 
+     * @see MessageDigest
+     */
+    public void on(boolean on) {
+        isOn = on;
+    }
+
+    /**
+     * Returns a string containing a concise, human-readable description of the
+     * receiver.
+     * 
+     * 
+     * @return String a printable representation for the receiver.
+     */
+    public String toString() {
+        return super.toString() + ", " + digest.toString() + //$NON-NLS-1$
+            (isOn ? ", is on" : ", is off"); //$NON-NLS-1$ //$NON-NLS-2$
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/DigestOutputStream.java b/libcore/security/src/main/java/java/security/DigestOutputStream.java
new file mode 100644
index 0000000..9bbc593
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/DigestOutputStream.java
@@ -0,0 +1,128 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class DigestOutputStream extends FilterOutputStream {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    protected MessageDigest digest;
+
+    // Indicates whether digest functionality is on or off
+    private boolean isOn = true;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public DigestOutputStream(OutputStream stream, MessageDigest digest) {
+        super(stream);
+        this.digest = digest;
+    }
+
+    /**
+     * Returns the MessageDigest which the receiver uses when computing the
+     * hash.
+     * 
+     * 
+     * @return MessageDigest the digest the receiver uses when computing the
+     *         hash.
+     */
+
+    public MessageDigest getMessageDigest() {
+        return digest;
+    }
+
+    /**
+     * Sets the MessageDigest which the receiver will use when computing the
+     * hash.
+     * 
+     * 
+     * @param digest
+     *            MessageDigest the digest to use when computing the hash.
+     * 
+     * @see MessageDigest
+     * @see #on
+     */
+    public void setMessageDigest(MessageDigest digest) {
+        this.digest = digest;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void write(int b) throws IOException {
+        // update digest only if digest functionality is on
+        if (isOn) {
+            digest.update((byte)b);
+        }
+        // write the byte
+        out.write(b);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void write(byte[] b, int off, int len) throws IOException {
+        // update digest only if digest functionality is on
+        if (isOn) {
+            digest.update(b, off, len);
+        }
+        // write len bytes
+        out.write(b, off, len);
+    }
+
+    /**
+     * Enables or disables the digest function (default is on).
+     * 
+     * 
+     * @param on
+     *            boolean true if the digest should be computed, and false
+     *            otherwise.
+     * 
+     * @see MessageDigest
+     */
+    public void on(boolean on) {
+        isOn = on;
+    }
+
+    /**
+     * Returns a string containing a concise, human-readable description of the
+     * receiver.
+     * 
+     * 
+     * @return String a printable representation for the receiver.
+     */
+    public String toString() {
+        return super.toString() + ", " + digest.toString() + //$NON-NLS-1$
+            (isOn ? ", is on" : ", is off"); //$NON-NLS-1$ //$NON-NLS-2$
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/DomainCombiner.java b/libcore/security/src/main/java/java/security/DomainCombiner.java
new file mode 100644
index 0000000..db072b6
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/DomainCombiner.java
@@ -0,0 +1,36 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Astapchuk
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * A DomainCombiner is a way to update the protection domains from an
+ * AccessControlContext
+ * 
+ */
+public interface DomainCombiner {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    ProtectionDomain[] combine(ProtectionDomain[] current,
+            ProtectionDomain[] assigned);
+}
diff --git a/libcore/security/src/main/java/java/security/GeneralSecurityException.java b/libcore/security/src/main/java/java/security/GeneralSecurityException.java
new file mode 100644
index 0000000..fb8d72e
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/GeneralSecurityException.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * This class represents the general security exception. Subclasses will
+ * represents specific security problems.
+ * 
+ */
+public class GeneralSecurityException extends Exception {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = 894798122053539237L;
+
+    /**
+     * Constructs a new instance of this class with its walkback and message
+     * filled in.
+     * 
+     * 
+     * @param msg
+     *            String The detail message for the exception.
+     */
+    public GeneralSecurityException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a new instance of this class with its walkback filled in.
+     * 
+     */
+    public GeneralSecurityException() {
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public GeneralSecurityException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public GeneralSecurityException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/Guard.java b/libcore/security/src/main/java/java/security/Guard.java
new file mode 100644
index 0000000..8042e34
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/Guard.java
@@ -0,0 +1,36 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * This interface is implemented by objects which wish to control access to
+ * other objects.
+ * 
+ */
+public interface Guard {
+
+    /** 
+     * @com.intel.drl.spec_ref 
+     */
+    public void checkGuard(Object object) throws SecurityException;
+}
diff --git a/libcore/security/src/main/java/java/security/GuardedObject.java b/libcore/security/src/main/java/java/security/GuardedObject.java
new file mode 100644
index 0000000..b284026
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/GuardedObject.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+/**
+ * GuardedObject controls access to an object, by checking all requests for the
+ * object with a Guard.
+ * 
+ */
+public class GuardedObject implements Serializable {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = -5240450096227834308L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private final Object object;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private final Guard guard;
+
+    /**
+     * Constructs a GuardedObject to protect access to the specified Object
+     * using the specified Guard.
+     * 
+     * @param object
+     *            the Object to guard
+     * @param guard
+     *            the Guard
+     */
+    public GuardedObject(Object object, Guard guard) {
+        this.object = object;
+        this.guard = guard;
+    }
+
+    /**
+     * Checks whether access should be granted to the object. If access is
+     * granted, this method returns the object. If it is not granted, then a
+     * <code>SecurityException</code> is thrown.
+     * 
+     * 
+     * @return the guarded object
+     * 
+     * @exception java.lang.SecurityException
+     *                If access is not granted to the object
+     */
+    public Object getObject() throws SecurityException {
+        if (guard != null) {
+            guard.checkGuard(object);
+        }
+        return object;
+    }
+
+    /** 
+     * Checks guard (if there is one) before performing a default serialization. 
+     */
+    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
+        if (guard != null) {
+            guard.checkGuard(object);
+        }
+        out.defaultWriteObject();
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/Identity.java b/libcore/security/src/main/java/java/security/Identity.java
new file mode 100644
index 0000000..7c3469d
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/Identity.java
@@ -0,0 +1,262 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Astapchuk
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.Serializable;
+import java.util.Vector;
+import java.util.Arrays;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * 
+ * @deprecated
+ */
+public abstract class Identity implements Principal, Serializable {
+    private static final long serialVersionUID = 3609922007826600659L;
+
+    private String name;
+
+    private PublicKey publicKey;
+
+    private String info = "no additional info"; //$NON-NLS-1$
+
+    private IdentityScope scope;
+
+    private Vector<Certificate> certificates;
+
+    protected Identity() {
+    }
+
+    public Identity(String name) {
+        this.name = name;
+    }
+
+    public Identity(String name, IdentityScope scope)
+            throws KeyManagementException {
+        this(name);
+        if (scope != null) {
+            scope.addIdentity(this);
+            this.scope = scope;
+        }
+    }
+
+    public void addCertificate(Certificate certificate)
+            throws KeyManagementException {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("addIdentityCertificate"); //$NON-NLS-1$
+        }
+        PublicKey certPK = certificate.getPublicKey();
+        if (publicKey != null) {
+            if (!checkKeysEqual(publicKey, certPK)) {
+                throw new KeyManagementException(Messages.getString("security.13")); //$NON-NLS-1$
+            }
+        } else {
+            publicKey = certPK;
+        }
+        if (certificates == null) {
+            certificates = new Vector<Certificate>();
+        }
+        certificates.add(certificate);
+    }
+
+
+      
+
+    private static boolean checkKeysEqual(PublicKey pk1, PublicKey pk2) {
+        // first, they should have the same format
+        // second, their encoded form must be the same
+
+        // assert(pk1 != null);
+        // assert(pk2 != null);
+
+        String format1 = pk1.getFormat();
+        String format2;
+        if ((pk2 == null)
+                || (((format2 = pk2.getFormat()) != null) ^ (format1 != null))
+                || ((format1 != null) && !format1.equals(format2))) {
+            return false;
+        }
+
+        return Arrays.equals(pk1.getEncoded(), pk2.getEncoded());
+    }
+
+
+      
+
+    public void removeCertificate(Certificate certificate)
+            throws KeyManagementException {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("removeIdentityCertificate"); //$NON-NLS-1$
+        }
+        if (certificates != null) {
+            certificates.removeElement(certificate);
+        }
+    }
+
+
+      
+
+    public Certificate[] certificates() {
+        if (certificates == null) {
+            return new Certificate[0];
+        }
+        Certificate[] ret = new Certificate[certificates.size()];
+        certificates.copyInto(ret);
+        return ret;
+    }
+
+
+      
+
+    protected boolean identityEquals(Identity identity) {
+        if (!name.equals(identity.name)) {
+            return false;
+        }
+
+        if (publicKey == null) {
+            return (identity.publicKey == null);
+        }
+
+        return checkKeysEqual(publicKey, identity.publicKey);
+    }
+
+
+      
+
+    public String toString(boolean detailed) {
+        String s = toString();
+        if (detailed) {
+            s += " " + info; //$NON-NLS-1$
+        }
+        return s;
+    }
+
+
+      
+
+    public final IdentityScope getScope() {
+        return scope;
+    }
+
+
+      
+
+    public void setPublicKey(PublicKey key) throws KeyManagementException {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("setIdentityPublicKey"); //$NON-NLS-1$
+        }
+        // this check does not always work  
+        if ((scope != null) && (key != null)) {
+            Identity i = scope.getIdentity(key);
+            //System.out.println("###DEBUG## Identity: "+i);
+            if ((i != null) && (i != this)) {
+                throw new KeyManagementException(Messages.getString("security.14")); //$NON-NLS-1$
+            }
+        }
+        this.publicKey = key;
+        certificates = null;
+    }
+
+
+      
+
+    public PublicKey getPublicKey() {
+        return publicKey;
+    }
+
+
+      
+
+    public void setInfo(String info) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("setIdentityInfo"); //$NON-NLS-1$
+        }
+        this.info = info;
+    }
+
+
+      
+
+    public String getInfo() {
+        return info;
+    }
+
+
+      
+
+    public final boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof Identity)) {
+            return false;
+        }
+        Identity i = (Identity) obj;
+        if ((name == i.name || (name != null && name.equals(i.name)))
+                && (scope == i.scope || (scope != null && scope.equals(i.scope)))) {
+            return true;
+        }
+        return identityEquals(i);
+    }
+
+
+      
+
+    public final String getName() {
+        return name;
+    }
+
+
+      
+
+    public int hashCode() {
+        int hash = 0;
+        if (name != null) {
+            hash += name.hashCode();
+        }
+        if (scope != null) {
+            hash += scope.hashCode();
+        }
+        return hash;
+    }
+
+
+      
+
+    public String toString() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("printIdentity"); //$NON-NLS-1$
+        }
+        String s = (this.name == null? "" : this.name);
+        if (scope != null) {
+            s += " [" + scope.getName() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        return s;
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/IdentityScope.java b/libcore/security/src/main/java/java/security/IdentityScope.java
new file mode 100644
index 0000000..daa8925
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/IdentityScope.java
@@ -0,0 +1,149 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Aleksei Y. Semenov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.util.Enumeration;
+
+import org.apache.harmony.security.SystemScope;
+
+
+/**
+ * @com.intel.drl.spec_ref 
+ * @deprecated
+ */
+public abstract class IdentityScope extends Identity {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = -2337346281189773310L;
+
+    // systemScope holds reference to the current system scope
+    private static IdentityScope systemScope;
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    protected IdentityScope() {
+        super();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public IdentityScope(String name) {
+        super(name);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public IdentityScope(String name, IdentityScope scope)
+            throws KeyManagementException {
+        super(name, scope);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public static IdentityScope getSystemScope() {
+        /* 
+         * Test shows that the implementation class name is read from security property
+         * "system.scope", and the class is only loaded from boot classpath. No default
+         * implementation as fallback, i.e., return null if fails to init an instance. 
+         */
+        if (systemScope == null) {
+            String className = AccessController.doPrivileged(new PrivilegedAction<String>(){
+                public String run() {
+                    return Security.getProperty("system.scope"); //$NON-NLS-1$
+                }
+            });
+            if(className != null){
+                try {
+                    systemScope = (IdentityScope) Class.forName(className).newInstance();
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return systemScope;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    protected static void setSystemScope(IdentityScope scope) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("setSystemScope"); //$NON-NLS-1$
+        }
+        systemScope = scope;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public abstract int size();
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public abstract Identity getIdentity(String name);
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public Identity getIdentity(Principal principal) {
+        return getIdentity(principal.getName());
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public abstract Identity getIdentity(PublicKey key);
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public abstract void addIdentity(Identity identity)
+            throws KeyManagementException;
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public abstract void removeIdentity(Identity identity)
+            throws KeyManagementException;
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public abstract Enumeration<Identity> identities();
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public String toString() {
+        return new StringBuffer(super.toString())
+                .append("[").append(size()).append("]").toString(); //$NON-NLS-1$ //$NON-NLS-2$
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/InvalidAlgorithmParameterException.java b/libcore/security/src/main/java/java/security/InvalidAlgorithmParameterException.java
new file mode 100644
index 0000000..adf494c
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/InvalidAlgorithmParameterException.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * This class represents invalid algorithm parameters to cryptographic services.
+ * 
+ */
+public class InvalidAlgorithmParameterException extends
+        GeneralSecurityException {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = 2864672297499471472L;
+
+    /**
+     * Constructs a new instance of this class with its walkback and message
+     * filled in.
+     * 
+     * 
+     * @param msg
+     *            String The detail message for the exception.
+     */
+    public InvalidAlgorithmParameterException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a new instance of this class with its walkback filled in.
+     * 
+     */
+    public InvalidAlgorithmParameterException() {
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public InvalidAlgorithmParameterException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public InvalidAlgorithmParameterException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/InvalidKeyException.java b/libcore/security/src/main/java/java/security/InvalidKeyException.java
new file mode 100644
index 0000000..45a3b30
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/InvalidKeyException.java
@@ -0,0 +1,70 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * Used when invalid cryptography keys are used.
+ * 
+ * @see Throwable
+ * @see Error
+ */
+public class InvalidKeyException extends KeyException {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = 5698479920593359816L;
+
+    /**
+     * Constructs a new instance of this class with its walkback and message
+     * filled in.
+     * 
+     * 
+     * @param msg
+     *            String The detail message for the exception.
+     */
+    public InvalidKeyException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a new instance of this class with its walkback filled in.
+     * 
+     */
+    public InvalidKeyException() {
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public InvalidKeyException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public InvalidKeyException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/InvalidParameterException.java b/libcore/security/src/main/java/java/security/InvalidParameterException.java
new file mode 100644
index 0000000..4af3b97
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/InvalidParameterException.java
@@ -0,0 +1,54 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * This exception is thrown when an invalid parameter is passed to a method.
+ * 
+ */
+public class InvalidParameterException extends IllegalArgumentException {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = -857968536935667808L;
+
+    /**
+     * Constructs a new instance of this class with its walkback and message
+     * filled in.
+     * 
+     * 
+     * @param msg
+     *            String The detail message for the exception.
+     */
+    public InvalidParameterException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a new instance of this class with its walkback filled in.
+     * 
+     */
+    public InvalidParameterException() {
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/Key.java b/libcore/security/src/main/java/java/security/Key.java
new file mode 100644
index 0000000..284d1a7
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/Key.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.Serializable;
+
+/**
+ * Defines the basic properties of all key objects.
+ * 
+ * @see PublicKey
+ */
+public interface Key extends Serializable {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public static final long serialVersionUID = 6603384152749567654L;
+
+    /**
+     * Returns the name of the algorithm that this key will work
+     * with. If the algorithm is unknown, it returns null.
+     * 
+     * @return String the receiver's algorithm
+     */
+    public String getAlgorithm();
+
+    /**
+     * Returns the name of the format used to encode the key, or null
+     * if it can not be encoded.
+     * 
+     * @return String the receiver's encoding format
+     */
+    public String getFormat();
+
+    /**
+     * Returns the encoded form of the receiver.
+     * 
+     * @return byte[] the encoded form of the receiver
+     */
+    public byte[] getEncoded();
+}
diff --git a/libcore/security/src/main/java/java/security/KeyException.java b/libcore/security/src/main/java/java/security/KeyException.java
new file mode 100644
index 0000000..fc83bc2
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/KeyException.java
@@ -0,0 +1,72 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * This class is the superclass of all classes which represent problems with
+ * keys.
+ * 
+ * 
+ * @see Throwable
+ * @see Error
+ */
+public class KeyException extends GeneralSecurityException {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = -7483676942812432108L;
+
+    /**
+     * Constructs a new instance of this class with its walkback and message
+     * filled in.
+     * 
+     * 
+     * @param msg
+     *            String The detail message for the exception.
+     */
+    public KeyException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a new instance of this class with its walkback filled in.
+     * 
+     */
+    public KeyException() {
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public KeyException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public KeyException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/KeyFactory.java b/libcore/security/src/main/java/java/security/KeyFactory.java
new file mode 100644
index 0000000..27ba6df
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/KeyFactory.java
@@ -0,0 +1,167 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris V. Kuznetsov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public class KeyFactory {
+    // The service name.
+    private static final String SERVICE = "KeyFactory"; //$NON-NLS-1$
+    
+    // The provider
+    private Provider provider;
+    
+    
+    // Used to access common engine functionality
+    static private Engine engine = new Engine(SERVICE);
+    
+    // The SPI implementation.
+    private KeyFactorySpi spiImpl; 
+    
+    // The algorithm.
+    private String algorithm;
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    protected KeyFactory(KeyFactorySpi keyFacSpi, 
+                         Provider provider,
+                         String algorithm) {
+        this.provider = provider;
+        this. algorithm = algorithm;
+        this.spiImpl = keyFacSpi;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    public static KeyFactory getInstance(String algorithm)
+                                throws NoSuchAlgorithmException {
+        if (algorithm == null) {
+            throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+        }
+        synchronized (engine) {
+            engine.getInstance(algorithm, null);
+            return new KeyFactory((KeyFactorySpi)engine.spi, engine.provider, algorithm);
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    public static KeyFactory getInstance(String algorithm, String provider)
+                                throws NoSuchAlgorithmException, NoSuchProviderException {
+        if ((provider == null) || (provider.length() == 0)) {
+            throw new IllegalArgumentException(Messages.getString("security.02")); //$NON-NLS-1$
+        }
+        Provider p = Security.getProvider(provider);
+        if (p == null) {
+            throw new NoSuchProviderException(Messages.getString("security.03", provider));  //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        return getInstance(algorithm, p);    
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    public static KeyFactory getInstance(String algorithm, Provider provider)
+                                 throws NoSuchAlgorithmException {
+        if (provider == null) {
+            throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
+        }
+        if (algorithm == null) {
+            throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+        }
+        synchronized (engine) {
+            engine.getInstance(algorithm, provider, null);
+            return new KeyFactory((KeyFactorySpi)engine.spi, provider, algorithm);
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    public final Provider getProvider() {
+        return provider;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    public final String getAlgorithm() {
+        return algorithm;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    public final PublicKey generatePublic(KeySpec keySpec)
+                                throws InvalidKeySpecException {
+        return spiImpl.engineGeneratePublic(keySpec);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    public final PrivateKey generatePrivate(KeySpec keySpec)
+                                throws InvalidKeySpecException {
+        return spiImpl.engineGeneratePrivate(keySpec);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    public final <T extends KeySpec> T getKeySpec(Key key,
+                                    Class<T> keySpec)
+                            throws InvalidKeySpecException {
+        return spiImpl.engineGetKeySpec(key, keySpec);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    public final Key translateKey(Key key)
+                        throws InvalidKeyException {
+        return spiImpl.engineTranslateKey(key);
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/KeyFactorySpi.java b/libcore/security/src/main/java/java/security/KeyFactorySpi.java
new file mode 100644
index 0000000..ee7a861
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/KeyFactorySpi.java
@@ -0,0 +1,64 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris V. Kuznetsov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public abstract class KeyFactorySpi {
+    
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    protected abstract PublicKey engineGeneratePublic(KeySpec keySpec) 
+                                    throws InvalidKeySpecException;
+    
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    protected abstract PrivateKey engineGeneratePrivate(KeySpec keySpec)
+                                    throws InvalidKeySpecException;
+    
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    protected abstract <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
+                                    throws InvalidKeySpecException;
+    //FIXME 1.5 signature: protected abstract <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec) throws InvalidKeySpecException
+    
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    protected abstract Key engineTranslateKey(Key key) throws InvalidKeyException;
+
+}
diff --git a/libcore/security/src/main/java/java/security/KeyManagementException.java b/libcore/security/src/main/java/java/security/KeyManagementException.java
new file mode 100644
index 0000000..ac7e70a
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/KeyManagementException.java
@@ -0,0 +1,63 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class KeyManagementException extends KeyException {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = 947674216157062695L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public KeyManagementException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public KeyManagementException() {
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public KeyManagementException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public KeyManagementException(Throwable cause) {
+        super(cause);
+    }
+
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/KeyPair.java b/libcore/security/src/main/java/java/security/KeyPair.java
new file mode 100644
index 0000000..4936259
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/KeyPair.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.Serializable;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public final class KeyPair implements Serializable {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = -7565189502268009837L;
+    private final PrivateKey privateKey;
+    private final PublicKey publicKey;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public KeyPair(PublicKey publicKey, PrivateKey privateKey) {
+        this.privateKey = privateKey;
+        this.publicKey = publicKey;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public PrivateKey getPrivate() {
+        return privateKey;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public PublicKey getPublic() {
+        return publicKey;
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/KeyPairGenerator.java b/libcore/security/src/main/java/java/security/KeyPairGenerator.java
new file mode 100644
index 0000000..e9fe0c4
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/KeyPairGenerator.java
@@ -0,0 +1,238 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * 
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public abstract class KeyPairGenerator extends KeyPairGeneratorSpi {
+
+    // Store KeyPairGenerator SERVICE name
+    private static final String SERVICE = "KeyPairGenerator"; //$NON-NLS-1$
+
+    // Used to access common engine functionality
+    private static Engine engine = new Engine(SERVICE);
+
+    // Store SecureRandom
+    private static SecureRandom random = new SecureRandom();
+
+    // Store used provider
+    private Provider provider;
+
+    // Store used algorithm
+    private String algorithm;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected KeyPairGenerator(String algorithm) {
+        this.algorithm = algorithm;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public String getAlgorithm() {
+        return algorithm;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     * throws NullPointerException when algorithm is null
+     */
+    public static KeyPairGenerator getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        if (algorithm == null) {
+            throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+        }
+        KeyPairGenerator result;
+        synchronized (engine) {
+            engine.getInstance(algorithm, null);
+            if (engine.spi instanceof KeyPairGenerator) {
+                result = (KeyPairGenerator) engine.spi;
+                result.algorithm = algorithm;
+                result.provider = engine.provider;
+                return result;
+            } else {
+                result = new KeyPairGeneratorImpl((KeyPairGeneratorSpi) engine.spi,
+                        engine.provider, algorithm);
+                return result;
+            }
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     * throws NullPointerException if algorithm is null (instead of
+     * NoSuchAlgorithmException) as in 1.4 release
+     */
+    public static KeyPairGenerator getInstance(String algorithm, String provider)
+            throws NoSuchAlgorithmException, NoSuchProviderException {
+        if ((provider == null) || (provider.length() == 0)) {
+            throw new IllegalArgumentException(
+                    Messages.getString("security.02")); //$NON-NLS-1$
+        }
+        Provider impProvider = Security.getProvider(provider);
+        if (impProvider == null) {
+            throw new NoSuchProviderException(provider);
+        }
+        return getInstance(algorithm, impProvider);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     * throws NullPointerException if algorithm is null (instead of
+     * NoSuchAlgorithmException) as in 1.4 release
+     */
+    public static KeyPairGenerator getInstance(String algorithm,
+            Provider provider) throws NoSuchAlgorithmException {
+        if (provider == null) {
+            throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
+        }
+        if (algorithm == null) {
+            throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+        }
+        KeyPairGenerator result;
+        synchronized (engine) {
+            engine.getInstance(algorithm, provider, null);
+            if (engine.spi instanceof KeyPairGenerator) {
+                result = (KeyPairGenerator) engine.spi;
+                result.algorithm = algorithm;
+                result.provider = provider;
+                return result;
+            } else {
+                result = new KeyPairGeneratorImpl((KeyPairGeneratorSpi) engine.spi,
+                        provider, algorithm);
+                return result;
+            }
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final Provider getProvider() {
+        return provider;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public void initialize(int keysize) {
+        initialize(keysize, random);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public void initialize(AlgorithmParameterSpec param)
+            throws InvalidAlgorithmParameterException {
+        initialize(param, random);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final KeyPair genKeyPair() {
+        return generateKeyPair();
+    }
+
+    public KeyPair generateKeyPair() {
+        return null;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public void initialize(int keysize, SecureRandom random) {
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public void initialize(AlgorithmParameterSpec param, SecureRandom random)
+            throws InvalidAlgorithmParameterException {
+    }
+
+    /**
+     * 
+     * Internal class: KeyPairGenerator implementation
+     * 
+     */
+    private static class KeyPairGeneratorImpl extends KeyPairGenerator {
+        // Save KeyPairGeneratorSpi
+        private KeyPairGeneratorSpi spiImpl;
+
+        // Implementation of KeyPaiGenerator constructor
+        // 
+        // @param KeyPairGeneratorSpi
+        // @param provider
+        // @param algorithm
+        private KeyPairGeneratorImpl(KeyPairGeneratorSpi keyPairGeneratorSpi,
+                Provider provider, String algorithm) {
+            super(algorithm);
+            super.provider = provider;
+            spiImpl = keyPairGeneratorSpi;
+        }
+
+        // implementation of initialize(int keysize, SecureRandom random)
+        // using corresponding spi initialize() method
+        public void initialize(int keysize, SecureRandom random) {
+            spiImpl.initialize(keysize, random);
+        }
+
+        // implementation of generateKeyPair()
+        // using corresponding spi generateKeyPair() method
+        public KeyPair generateKeyPair() {
+            return spiImpl.generateKeyPair();
+        }
+
+        // implementation of initialize(int keysize, SecureRandom random)
+        // using corresponding spi initialize() method
+        public void initialize(AlgorithmParameterSpec param, SecureRandom random)
+                throws InvalidAlgorithmParameterException {
+            spiImpl.initialize(param, random);
+        }
+
+    }
+
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/KeyPairGeneratorSpi.java b/libcore/security/src/main/java/java/security/KeyPairGeneratorSpi.java
new file mode 100644
index 0000000..8e51367
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/KeyPairGeneratorSpi.java
@@ -0,0 +1,62 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public abstract class KeyPairGeneratorSpi {
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public KeyPairGeneratorSpi() {
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public abstract KeyPair generateKeyPair();
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public abstract void initialize(int keysize, SecureRandom random);
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public void initialize(AlgorithmParameterSpec params, SecureRandom random)
+            throws InvalidAlgorithmParameterException {
+        throw new UnsupportedOperationException(Messages.getString("security.2E")); //$NON-NLS-1$
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/KeyRep.java b/libcore/security/src/main/java/java/security/KeyRep.java
new file mode 100644
index 0000000..957fdac
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/KeyRep.java
@@ -0,0 +1,148 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.security.spec.X509EncodedKeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.InvalidKeySpecException;
+
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class KeyRep implements Serializable {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = -4757683898830641853L;
+    // Key type
+    private final Type type;
+    // Key algorithm name
+    private final String algorithm;
+    // Key encoding format
+    private final String format;
+    // Key encoding
+    private byte[] encoded;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public KeyRep(Type type,
+            String algorithm, String format, byte[] encoded) {
+        this.type = type;
+        this.algorithm = algorithm;
+        this.format = format;
+        this.encoded = encoded;
+        if(this.type == null) {
+            throw new NullPointerException(Messages.getString("security.07")); //$NON-NLS-1$
+        }
+        if(this.algorithm == null) {
+            throw new NullPointerException(Messages.getString("security.08")); //$NON-NLS-1$
+        }
+        if(this.format == null) {
+            throw new NullPointerException(Messages.getString("security.09")); //$NON-NLS-1$
+        }
+        if(this.encoded == null) {
+            throw new NullPointerException(Messages.getString("security.0A")); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    protected Object readResolve() throws ObjectStreamException {
+        switch (type) {
+        case SECRET:
+            if ("RAW".equals(format)) { //$NON-NLS-1$
+                try {
+                    return new SecretKeySpec(encoded, algorithm);
+                } catch (IllegalArgumentException e) {
+                    throw new NotSerializableException(
+                            Messages.getString("security.0B", e)); //$NON-NLS-1$
+                }
+            }
+            throw new NotSerializableException(
+                Messages.getString("security.0C", type, format)); //$NON-NLS-1$
+        case PUBLIC:
+            if ("X.509".equals(format)) { //$NON-NLS-1$
+                try {
+                    KeyFactory kf = KeyFactory.getInstance(algorithm);
+                    return kf.generatePublic(new X509EncodedKeySpec(encoded));
+                } catch (NoSuchAlgorithmException e) {
+                    throw new NotSerializableException(
+                            Messages.getString("security.0D", e)); //$NON-NLS-1$
+                }
+                catch (InvalidKeySpecException e) {
+                    throw new NotSerializableException(
+                            Messages.getString("security.0D", e)); //$NON-NLS-1$
+                }
+            }
+            throw new NotSerializableException(
+                Messages.getString("security.0C", type, format)); //$NON-NLS-1$
+        case PRIVATE:
+            if ("PKCS#8".equals(format)) { //$NON-NLS-1$
+                try {
+                    KeyFactory kf = KeyFactory.getInstance(algorithm);
+                    return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
+                } catch (NoSuchAlgorithmException e) {
+                    throw new NotSerializableException(
+                            Messages.getString("security.0D", e)); //$NON-NLS-1$
+                }
+                catch (InvalidKeySpecException e) {
+                    throw new NotSerializableException(
+                            Messages.getString("security.0D", e)); //$NON-NLS-1$
+                }
+            }
+            throw new NotSerializableException(
+                Messages.getString("security.0C", type, format)); //$NON-NLS-1$
+        }
+        throw new NotSerializableException(Messages.getString("security.0E", type)); //$NON-NLS-1$
+    }
+
+    // Makes defensive copy of key encoding
+    private void readObject(ObjectInputStream is)
+        throws IOException, ClassNotFoundException {
+        is.defaultReadObject();
+        byte[] new_encoded = new byte[encoded.length];
+        System.arraycopy(encoded, 0, new_encoded, 0, new_encoded.length);
+        encoded = new_encoded;    
+    }
+
+    /**
+     * Supported key types
+     */
+    public static enum Type {
+        SECRET,
+        PUBLIC,
+        PRIVATE
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/KeyStore.java b/libcore/security/src/main/java/java/security/KeyStore.java
new file mode 100644
index 0000000..9a6699f
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/KeyStore.java
@@ -0,0 +1,1085 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Enumeration;
+
+import javax.crypto.SecretKey;
+import javax.security.auth.DestroyFailedException;
+import javax.security.auth.Destroyable;
+import javax.security.auth.callback.CallbackHandler;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+public class KeyStore {
+
+    // Store KeyStore SERVICE name
+    private static final String SERVICE = "KeyStore"; //$NON-NLS-1$
+
+    // Used to access common engine functionality
+    private static Engine engine = new Engine(SERVICE);
+
+    //  Store KeyStore property name
+    private static final String PROPERTYNAME = "keystore.type"; //$NON-NLS-1$
+
+    //  Store default KeyStore type
+    private static final String DEFAULT_KEYSTORE_TYPE = "jks"; //$NON-NLS-1$
+
+    // Message to report about non-initialized key store object
+    // BEGIN android-changed
+    private static String NOTINITKEYSTORE;
+    // END android-changed
+
+    // Store KeyStore state (initialized or not)
+    private boolean isInit;
+
+    // Store used KeyStoreSpi
+    private final KeyStoreSpi implSpi;
+
+    // Store used provider
+    private final Provider provider;
+
+    // Store used type
+    private final String type;
+
+    protected KeyStore(KeyStoreSpi keyStoreSpi, Provider provider, String type) {
+        this.type = type;
+        this.provider = provider;
+        this.implSpi = keyStoreSpi;
+        isInit = false;
+    }
+
+    // BEGIN android-added
+    /**
+     * Throws the standard "keystore not initialized" exception.
+     */
+    private static void throwNotInitialized() throws KeyStoreException {
+        if (NOTINITKEYSTORE == null) {
+            NOTINITKEYSTORE = Messages.getString("security.4F"); //$NON-NLS-1$
+        }
+        throw new KeyStoreException(NOTINITKEYSTORE);
+    }
+    // END android-added
+    
+    /**
+     * @throws NullPointerException if type is null
+     */
+    public static KeyStore getInstance(String type) throws KeyStoreException {
+        if (type == null) {
+            throw new NullPointerException(Messages.getString("security.07")); //$NON-NLS-1$
+        }
+        synchronized (engine) {
+            try {
+                engine.getInstance(type, null);
+                return new KeyStore((KeyStoreSpi) engine.spi, engine.provider, type);
+            } catch (NoSuchAlgorithmException e) {
+                throw new KeyStoreException(e.getMessage());
+            }
+        }
+    }
+
+    /**
+     * 
+     * 
+     * @throws NullPointerException if type is null (instead of
+     * NoSuchAlgorithmException) as in 1.4 release
+     */
+    public static KeyStore getInstance(String type, String provider)
+            throws KeyStoreException, NoSuchProviderException {
+        if ((provider == null) || (provider.length() == 0)) {
+            throw new IllegalArgumentException(Messages.getString("security.02")); //$NON-NLS-1$
+        }
+        Provider impProvider = Security.getProvider(provider);
+        if (impProvider == null) {
+            throw new NoSuchProviderException(provider);
+        }
+        try {
+            return getInstance(type, impProvider);
+        } catch (Exception e) {
+            throw new KeyStoreException(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 
+     * 
+     * throws NullPointerException if type is null (instead of
+     * NoSuchAlgorithmException) as in 1.4 release
+     */
+    public static KeyStore getInstance(String type, Provider provider)
+            throws KeyStoreException {
+        // check parameters
+        if (provider == null) {
+            throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
+        }
+        if (type == null) {
+            throw new NullPointerException(Messages.getString("security.07")); //$NON-NLS-1$
+        }
+        // return KeyStore instance
+        synchronized (engine) {
+            try {
+                engine.getInstance(type, provider, null);
+                return new KeyStore((KeyStoreSpi) engine.spi, provider, type);
+            } catch (Exception e) {
+            // override exception
+                throw new KeyStoreException(e.getMessage());
+            }
+        }
+    }
+
+    /**
+     * 
+     *  
+     */
+    public static final String getDefaultType() {
+        String dt = AccessController.doPrivileged(
+                new PrivilegedAction<String>() {
+                    public String run() {
+                        return Security.getProperty(PROPERTYNAME);
+                    }
+                }
+            );
+        return (dt == null ? DEFAULT_KEYSTORE_TYPE : dt);
+    }
+
+    /**
+     * 
+     *  
+     */
+    public final Provider getProvider() {
+        return provider;
+    }
+
+    /**
+     * 
+     *  
+     */
+    public final String getType() {
+        return type;
+    }
+
+    /**
+     * 
+     *  
+     */
+    public final Key getKey(String alias, char[] password)
+            throws KeyStoreException, NoSuchAlgorithmException,
+            UnrecoverableKeyException {
+        if (!isInit) {
+            // BEGIN android-changed
+            throwNotInitialized();
+            // END android-changed
+        }
+        return implSpi.engineGetKey(alias, password);
+    }
+
+    /**
+     * 
+     *  
+     */
+    public final Certificate[] getCertificateChain(String alias)
+            throws KeyStoreException {
+        if (!isInit) {
+            // BEGIN android-changed
+            throwNotInitialized();
+            // END android-changed
+        }
+        return implSpi.engineGetCertificateChain(alias);
+    }
+
+    /**
+     * 
+     *  
+     */
+    public final Certificate getCertificate(String alias)
+            throws KeyStoreException {
+        if (!isInit) {
+            // BEGIN android-changed
+            throwNotInitialized();
+            // END android-changed
+        }
+        return implSpi.engineGetCertificate(alias);
+    }
+
+    /**
+     * 
+     *  
+     */
+    public final Date getCreationDate(String alias) throws KeyStoreException {
+        if (!isInit) {
+            // BEGIN android-changed
+            throwNotInitialized();
+            // END android-changed
+        }
+        return implSpi.engineGetCreationDate(alias);
+    }
+
+    /**
+     * 
+     * 
+     * 1.4.2 and 1.5 releases throw unspecified NullPointerException -
+     * when alias is null IllegalArgumentException - when password is null
+     * IllegalArgumentException - when key is instance of PrivateKey and chain
+     * is null or empty
+     */
+    public final void setKeyEntry(String alias, Key key, char[] password,
+            Certificate[] chain) throws KeyStoreException {
+        if (!isInit) {
+            // BEGIN android-changed
+            throwNotInitialized();
+            // END android-changed
+        }
+
+        // Certificate chain is required for PrivateKey
+        if (null != key && key instanceof PrivateKey
+                && (chain == null || chain.length == 0)) {
+            throw new IllegalArgumentException(Messages
+                    .getString("security.52")); //$NON-NLS-1$
+        }
+        implSpi.engineSetKeyEntry(alias, key, password, chain);
+    }
+
+    /**
+     * 
+     *  
+     */
+    public final void setKeyEntry(String alias, byte[] key, Certificate[] chain)
+            throws KeyStoreException {
+        if (!isInit) {
+            // BEGIN android-changed
+            throwNotInitialized();
+            // END android-changed
+        }
+        implSpi.engineSetKeyEntry(alias, key, chain);
+    }
+
+    /**
+     * 
+     * 
+     * 1.4.2 and 1.5 releases throw unspecified NullPointerException
+     * when alias is null
+     */
+    public final void setCertificateEntry(String alias, Certificate cert)
+            throws KeyStoreException {
+        if (!isInit) {
+            // BEGIN android-changed
+            throwNotInitialized();
+            // END android-changed
+        }
+        implSpi.engineSetCertificateEntry(alias, cert);
+    }
+
+    /**
+     * 
+     * 
+     * 1.4.2 and 1.5 releases throw NullPointerException when alias is null
+     */
+    public final void deleteEntry(String alias) throws KeyStoreException {
+        if (!isInit) {
+            // BEGIN android-changed
+            throwNotInitialized();
+            // END android-changed
+        }
+        if (alias == null) {
+            throw new NullPointerException(Messages.getString("security.3F")); //$NON-NLS-1$
+        }
+        implSpi.engineDeleteEntry(alias);
+    }
+
+    /**
+     * 
+     */
+    public final Enumeration<String> aliases() throws KeyStoreException {
+        if (!isInit) {
+            // BEGIN android-changed
+            throwNotInitialized();
+            // END android-changed
+        }
+        return implSpi.engineAliases();
+    }
+
+    /**
+     * 
+     * 
+     * 1.4.2 and 1.5 releases throw unspecified NullPointerException when
+     * alias is null
+     */
+    public final boolean containsAlias(String alias) throws KeyStoreException {
+        if (!isInit) {
+            // BEGIN android-changed
+            throwNotInitialized();
+            // END android-changed
+        }
+        if (alias == null) {
+            throw new NullPointerException(Messages.getString("security.3F")); //$NON-NLS-1$
+        }
+        return implSpi.engineContainsAlias(alias);
+    }
+
+    /**
+     * 
+     *  
+     */
+    public final int size() throws KeyStoreException {
+        if (!isInit) {
+            // BEGIN android-changed
+            throwNotInitialized();
+            // END android-changed
+        }
+        return implSpi.engineSize();
+    }
+
+    /**
+     * 
+     * 
+     * jdk1.4.2 and 1.5 releases throw unspecified NullPointerException
+     * when alias is null
+     */
+    public final boolean isKeyEntry(String alias) throws KeyStoreException {
+        if (!isInit) {
+            // BEGIN android-changed
+            throwNotInitialized();
+            // END android-changed
+        }
+        if (alias == null) {
+            throw new NullPointerException(Messages.getString("security.3F")); //$NON-NLS-1$
+        }
+        return implSpi.engineIsKeyEntry(alias);
+    }
+
+    /**
+     * 
+     * 
+     * jdk1.4.2 and 1.5 releases throw unspecified NullPointerException
+     * when alias is null
+     */
+    public final boolean isCertificateEntry(String alias)
+            throws KeyStoreException {
+        if (!isInit) {
+            // BEGIN android-changed
+            throwNotInitialized();
+            // END android-changed
+        }
+        if (alias == null) {
+            throw new NullPointerException(Messages.getString("security.3F")); //$NON-NLS-1$
+        }
+        return implSpi.engineIsCertificateEntry(alias);
+    }
+
+    /**
+     * 
+     *  
+     */
+    public final String getCertificateAlias(Certificate cert)
+            throws KeyStoreException {
+        if (!isInit) {
+            // BEGIN android-changed
+            throwNotInitialized();
+            // END android-changed
+        }
+        return implSpi.engineGetCertificateAlias(cert);
+    }
+
+    /**
+     * 
+     * 
+     * throws IOException when stream or password is null
+     */
+    public final void store(OutputStream stream, char[] password)
+            throws KeyStoreException, IOException, NoSuchAlgorithmException,
+            CertificateException {
+        if (!isInit) {
+            // BEGIN android-changed
+            throwNotInitialized();
+            // END android-changed
+        }
+        if (stream == null) {
+            throw new IOException(Messages.getString("security.51")); //$NON-NLS-1$
+        }
+        if (password == null) {
+            throw new IOException(Messages.getString("security.50")); //$NON-NLS-1$
+        }
+        implSpi.engineStore(stream, password);
+    }
+
+    /**
+     * 
+     *  
+     */
+    public final void store(LoadStoreParameter param) throws KeyStoreException,
+            IOException, NoSuchAlgorithmException, CertificateException {
+        if (!isInit) {
+            // BEGIN android-changed
+            throwNotInitialized();
+            // END android-changed
+        }
+        implSpi.engineStore(param);
+    }
+
+    /**
+     * 
+     *  
+     */
+    public final void load(InputStream stream, char[] password)
+            throws IOException, NoSuchAlgorithmException, CertificateException {
+        implSpi.engineLoad(stream, password);
+        isInit = true;
+    }
+
+    /**
+     * 
+     *  
+     */
+    public final void load(LoadStoreParameter param) throws IOException,
+            NoSuchAlgorithmException, CertificateException {
+        implSpi.engineLoad(param);
+        isInit = true;
+    }
+
+    /**
+     * 
+     *  
+     */
+    public final Entry getEntry(String alias, ProtectionParameter param)
+            throws NoSuchAlgorithmException, UnrecoverableEntryException,
+            KeyStoreException {
+        if (alias == null) {
+            throw new NullPointerException(Messages.getString("security.3F")); //$NON-NLS-1$
+        }
+        if (!isInit) {
+            // BEGIN android-changed
+            throwNotInitialized();
+            // END android-changed
+        }
+        return implSpi.engineGetEntry(alias, param);
+    }
+
+    /**
+     * 
+     * 
+     * 1.5 release throws unspecified NullPointerException when alias or
+     * entry is null
+     */
+    public final void setEntry(String alias, Entry entry,
+            ProtectionParameter param) throws KeyStoreException {
+        if (!isInit) {
+            // BEGIN android-changed
+            throwNotInitialized();
+            // END android-changed
+        }
+        if (alias == null) {
+            throw new NullPointerException(Messages.getString("security.3F")); //$NON-NLS-1$
+        }
+        if (entry == null) {
+            throw new NullPointerException(Messages.getString("security.39")); //$NON-NLS-1$
+        }
+        implSpi.engineSetEntry(alias, entry, param);
+    }
+
+    /**
+     * 
+     */
+    public final boolean entryInstanceOf(String alias, 
+            Class<? extends KeyStore.Entry> entryClass)
+            throws KeyStoreException {
+        if (alias == null) {
+            throw new NullPointerException(Messages.getString("security.3F")); //$NON-NLS-1$
+        }
+        if (entryClass == null) {
+            throw new NullPointerException(Messages.getString("security.40")); //$NON-NLS-1$
+        }
+
+        if (!isInit) {
+            // BEGIN android-changed
+            throwNotInitialized();
+            // END android-changed
+        }
+        return implSpi.engineEntryInstanceOf(alias, entryClass);
+    }
+
+    /**
+     * 
+     * 
+     * 
+     */
+    public abstract static class Builder {
+        /**
+         * 
+         *  
+         */
+        protected Builder() {
+        }
+
+        /**
+         * 
+         *  
+         */
+        public abstract KeyStore getKeyStore() throws KeyStoreException;
+
+        /**
+         * 
+         *  
+         */
+        public abstract ProtectionParameter getProtectionParameter(String alise)
+                throws KeyStoreException;
+
+        /**
+         * 
+         *  
+         */
+        public static Builder newInstance(KeyStore keyStore,
+                ProtectionParameter protectionParameter) {
+            if (keyStore == null) {
+                throw new NullPointerException(Messages.getString("security.41")); //$NON-NLS-1$
+            }
+            if (protectionParameter == null) {
+                throw new NullPointerException(Messages.getString("security.42")); //$NON-NLS-1$
+            }
+
+            if (!keyStore.isInit) {
+                throw new IllegalArgumentException(NOTINITKEYSTORE);
+            }
+            return new BuilderImpl(keyStore, protectionParameter,
+                    null, null, null, null);
+        }
+
+        /**
+         * 
+         *  
+         */
+        public static Builder newInstance(String type, Provider provider,
+                File file, ProtectionParameter protectionParameter) {
+            // check null parameters
+            if (type == null) {
+                throw new NullPointerException(Messages.getString("security.07")); //$NON-NLS-1$
+            }
+            if (protectionParameter == null) {
+                throw new NullPointerException(Messages.getString("security.42")); //$NON-NLS-1$
+            }
+            if (file == null) {
+                throw new NullPointerException(Messages.getString("security.43")); //$NON-NLS-1$
+            }
+            // protection parameter should be PasswordProtection or
+            // CallbackHandlerProtection
+            if (!(protectionParameter instanceof PasswordProtection)
+                    && !(protectionParameter instanceof CallbackHandlerProtection)) {
+                throw new IllegalArgumentException(Messages.getString("security.35")); //$NON-NLS-1$
+            }
+            // check file parameter
+            if (!file.exists()) {
+                throw new IllegalArgumentException(Messages.getString("security.44", file.getName())); //$NON-NLS-1$
+            }
+            if (!file.isFile()) {
+                throw new IllegalArgumentException(Messages.getString("security.45", file.getName())); //$NON-NLS-1$
+            }
+            // create new instance
+            return new BuilderImpl(null, protectionParameter, file,
+                    type, provider, AccessController.getContext());
+        }
+
+        /**
+         * 
+         *  
+         */
+        public static Builder newInstance(String type, Provider provider,
+                ProtectionParameter protectionParameter) {
+            if (type == null) {
+                throw new NullPointerException(Messages.getString("security.07")); //$NON-NLS-1$
+            }
+            if (protectionParameter == null) {
+                throw new NullPointerException(Messages.getString("security.42")); //$NON-NLS-1$
+            }
+            return new BuilderImpl(null, protectionParameter, null,
+                    type, provider, AccessController.getContext());
+        }
+
+        /*
+         * This class is implementation of abstract class KeyStore.Builder
+         * 
+         * @author Vera Petrashkova
+         * 
+         */
+        private static class BuilderImpl extends Builder {
+            // Store used KeyStore
+            private KeyStore keyStore;
+
+            // Store used ProtectionParameter
+            private ProtectionParameter protParameter;
+
+            // Store used KeyStore type
+            private final String typeForKeyStore;
+
+            // Store used KeyStore provider
+            private final Provider providerForKeyStore;
+
+            // Store used file for KeyStore loading
+            private final File fileForLoad;
+
+            // Store getKeyStore method was invoked or not for KeyStoreBuilder
+            private boolean isGetKeyStore = false;
+
+            // Store last Exception in getKeyStore()
+            private KeyStoreException lastException;
+
+            // Store AccessControlContext which is used in getKeyStore() method
+            private final AccessControlContext accControlContext;
+
+            //
+            // Constructor BuilderImpl initializes private fields: keyStore,
+            // protParameter, typeForKeyStore providerForKeyStore fileForLoad,
+            // isGetKeyStore
+            //
+            BuilderImpl(KeyStore ks, ProtectionParameter pp, File file,
+                    String type, Provider provider, AccessControlContext context) {
+                super();
+                keyStore = ks;
+                protParameter = pp;
+                fileForLoad = file;
+                typeForKeyStore = type;
+                providerForKeyStore = provider;
+                isGetKeyStore = false;
+                lastException = null;
+                accControlContext = context;
+            }
+
+            //
+            // Implementation of abstract getKeyStore() method If
+            // KeyStoreBuilder encapsulates KeyStore object then this object is
+            // returned
+            // 
+            // If KeyStoreBuilder encapsulates KeyStore type and provider then
+            // KeyStore is created using these parameters. If KeyStoreBuilder
+            // encapsulates file and ProtectionParameter then KeyStore data are
+            // loaded from FileInputStream that is created on file. If file is
+            // not defined then KeyStore object is initialized with null
+            // InputStream and null password.
+            // 
+            // Result KeyStore object is returned.
+            //
+            public synchronized KeyStore getKeyStore() throws KeyStoreException {
+                // If KeyStore was created but in final block some exception was
+                // thrown
+                // then it was stored in lastException variable and will be
+                // thrown
+                // all subsequent calls of this method.
+                if (lastException != null) {
+                    throw lastException;
+                }
+                if (keyStore != null) {
+                    isGetKeyStore = true;
+                    return keyStore;
+                }
+
+                try {
+                    final KeyStore ks;
+                    final char[] passwd;
+
+                    // get KeyStore instance using type or type and provider
+                    ks = (providerForKeyStore == null ? KeyStore
+                            .getInstance(typeForKeyStore) : KeyStore
+                            .getInstance(typeForKeyStore, providerForKeyStore));
+                    // protection parameter should be PasswordProtection
+                    // or CallbackHandlerProtection
+                    if (protParameter instanceof PasswordProtection) {
+                        passwd = ((PasswordProtection) protParameter)
+                                .getPassword();
+                    } else if (protParameter instanceof CallbackHandlerProtection) {
+                        passwd = KeyStoreSpi
+                                .getPasswordFromCallBack(protParameter);
+                    } else {
+                        throw new KeyStoreException(Messages.getString("security.35")); //$NON-NLS-1$
+                    }
+
+                    // load KeyStore from file
+                    AccessController.doPrivileged(
+                            new PrivilegedExceptionAction<Object>() {
+                                public Object run() throws Exception {
+                                    if (fileForLoad != null) {
+                                        FileInputStream fis = null;
+                                        try {
+                                            fis = new FileInputStream(fileForLoad);
+                                            ks.load(fis, passwd);
+                                        } finally {
+                                            // close file input stream
+                                            if( fis != null ) {
+                                                fis.close();   
+                                            }
+                                        }
+                                    } else {
+                                        ks.load(new TmpLSParameter(
+                                                protParameter));
+                                    }
+                                    return null;
+                                }
+                            }, accControlContext);
+
+                    
+                    isGetKeyStore = true;
+                    keyStore = ks;
+                    return keyStore;
+                } catch (KeyStoreException e) {
+                    // Store exception
+                    throw lastException = e;
+                } catch (Exception e) {
+                    // Override exception
+                    throw lastException = new KeyStoreException(e);
+                }
+            }
+
+            //
+            // This is implementation of abstract method
+            // getProtectionParameter(String alias)
+            // 
+            // Return: ProtectionParameter to get Entry which was saved in
+            // KeyStore with defined alias
+            //
+            public synchronized ProtectionParameter getProtectionParameter(
+                    String alias) throws KeyStoreException {
+                if (alias == null) {
+                    throw new NullPointerException(Messages.getString("security.3F")); //$NON-NLS-1$
+                }
+                if (!isGetKeyStore) {
+                    throw new IllegalStateException(Messages.getString("security.46")); //$NON-NLS-1$
+                }
+                return protParameter;
+            }
+        }
+
+        // BEGIN android-note
+        // Added "static" to the class declaration below.
+        // END android-note
+        /*
+         * Implementation of LoadStoreParameter interface
+         * 
+         * @author Vera Petrashkova
+         */
+        private static class TmpLSParameter implements LoadStoreParameter {
+
+            // Store used protection parameter
+            private final ProtectionParameter protPar;
+
+            /**
+             * Creates TmpLoadStoreParameter object
+             */
+            public TmpLSParameter(ProtectionParameter protPar) {
+                this.protPar = protPar;
+            }
+
+            /**
+             * This method returns protection parameter
+             */
+            public ProtectionParameter getProtectionParameter() {
+                return protPar;
+            }
+        }
+    }
+
+    /**
+     * 
+     * 
+     * 
+     */
+    public static class CallbackHandlerProtection implements
+            ProtectionParameter {
+        // Store CallbackHandler
+        private final CallbackHandler callbackHandler;
+
+        /**
+         * 
+         *  
+         */
+        public CallbackHandlerProtection(CallbackHandler handler) {
+            if (handler == null) {
+                throw new NullPointerException(Messages.getString("security.47")); //$NON-NLS-1$
+            }
+            this.callbackHandler = handler;
+        }
+
+        /**
+         * 
+         *  
+         */
+        public CallbackHandler getCallbackHandler() {
+            return callbackHandler;
+        }
+    }
+
+    /**
+     * 
+     * 
+     * 
+     */
+    public static interface Entry {
+    }
+
+    /**
+     * 
+     * 
+     * 
+     */
+    public static interface LoadStoreParameter {
+        /**
+         * 
+         *  
+         */
+        public ProtectionParameter getProtectionParameter();
+    }
+
+    /**
+     * 
+     * 
+     * 
+     */
+    public static class PasswordProtection implements ProtectionParameter,
+            Destroyable {
+
+        // Store password
+        private char[] password;
+
+        private boolean isDestroyed = false;
+
+        /**
+         * 
+         *  
+         */
+        public PasswordProtection(char[] password) {
+            this.password = password;
+        }
+
+        /**
+         * 
+         *  
+         */
+        public synchronized char[] getPassword() {
+            if (isDestroyed) {
+                throw new IllegalStateException(Messages.getString("security.36")); //$NON-NLS-1$
+            }
+            return password;
+        }
+
+        /**
+         * 
+         *  
+         */
+        public synchronized void destroy() throws DestroyFailedException {
+            isDestroyed = true;
+            if (password != null) {
+                Arrays.fill(password, '\u0000');
+                password = null;
+            }
+        }
+
+        /**
+         * 
+         *  
+         */
+        public synchronized boolean isDestroyed() {
+            return isDestroyed;
+        }
+    }
+
+    /**
+     * 
+     * 
+     * 
+     */
+    public static interface ProtectionParameter {
+    }
+
+    /**
+     * 
+     * 
+     * 
+     */
+    public static final class PrivateKeyEntry implements Entry {
+        // Store Certificate chain
+        private Certificate[] chain;
+
+        // Store PrivateKey
+        private PrivateKey privateKey;
+
+        /**
+         * 
+         *  
+         */
+        public PrivateKeyEntry(PrivateKey privateKey, Certificate[] chain) {
+            if (privateKey == null) {
+                throw new NullPointerException(Messages.getString("security.48")); //$NON-NLS-1$
+            }
+            if (chain == null) {
+                throw new NullPointerException(Messages.getString("security.49")); //$NON-NLS-1$
+            }
+
+            if (chain.length == 0) {
+                throw new IllegalArgumentException(Messages.getString("security.4A")); //$NON-NLS-1$
+            }
+            // Match algorithm of private key and algorithm of public key from
+            // the end certificate
+            String s = chain[0].getType();
+            if (!(chain[0].getPublicKey().getAlgorithm()).equals(privateKey
+                    .getAlgorithm())) {
+                throw new IllegalArgumentException(Messages.getString("security.4B")); //$NON-NLS-1$
+            }
+            // Match certificate types
+            for (int i = 1; i < chain.length; i++) {
+                if (!s.equals(chain[i].getType())) {
+                    throw new IllegalArgumentException(
+                            Messages.getString("security.4C")); //$NON-NLS-1$
+                }
+            }
+            // clone chain - this.chain = (Certificate[])chain.clone();
+            this.chain = new Certificate[chain.length];
+            System.arraycopy(chain, 0, this.chain, 0, chain.length);
+            this.privateKey = privateKey;
+        }
+
+        /**
+         * 
+         *  
+         */
+        public PrivateKey getPrivateKey() {
+            return privateKey;
+        }
+
+        /**
+         * 
+         *  
+         */
+        public Certificate[] getCertificateChain() {
+            return chain;
+        }
+
+        /**
+         * 
+         *  
+         */
+        public Certificate getCertificate() {
+            return chain[0];
+        }
+
+        /**
+         * 
+         *  
+         */
+        public String toString() {
+            StringBuffer sb = new StringBuffer(
+                    "PrivateKeyEntry: number of elements in certificate chain is "); //$NON-NLS-1$
+            sb.append(Integer.toString(chain.length));
+            sb.append("\n"); //$NON-NLS-1$
+            for (int i = 0; i < chain.length; i++) {
+                sb.append(chain[i].toString());
+                sb.append("\n"); //$NON-NLS-1$
+            }
+            return sb.toString();
+        }
+    }
+
+    /**
+     * 
+     * 
+     * 
+     */
+    public static final class SecretKeyEntry implements Entry {
+
+        // Store SecretKey
+        private final SecretKey secretKey;
+
+        /**
+         * 
+         *  
+         */
+        public SecretKeyEntry(SecretKey secretKey) {
+            if (secretKey == null) {
+                throw new NullPointerException(Messages.getString("security.4D")); //$NON-NLS-1$
+            }
+            this.secretKey = secretKey;
+        }
+
+        /**
+         * 
+         *  
+         */
+        public SecretKey getSecretKey() {
+            return secretKey;
+        }
+
+        /**
+         * 
+         *  
+         */
+        public String toString() {
+            StringBuffer sb = new StringBuffer("SecretKeyEntry: algorithm - "); //$NON-NLS-1$
+            sb.append(secretKey.getAlgorithm());
+            return sb.toString();
+        }
+    }
+
+    /**
+     * 
+     * 
+     * 
+     */
+    public static final class TrustedCertificateEntry implements Entry {
+
+        // Store trusted Certificate
+        private final Certificate trustCertificate;
+
+        /**
+         * 
+         *  
+         */
+        public TrustedCertificateEntry(Certificate trustCertificate) {
+            if (trustCertificate == null) {
+                throw new NullPointerException(Messages.getString("security.4E")); //$NON-NLS-1$
+            }
+            this.trustCertificate = trustCertificate;
+        }
+
+        /**
+         * 
+         *  
+         */
+        public Certificate getTrustedCertificate() {
+            return trustCertificate;
+        }
+
+        /**
+         * 
+         *  
+         */
+        public String toString() {
+            return "Trusted certificate entry:\n" + trustCertificate; //$NON-NLS-1$
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/KeyStoreException.java b/libcore/security/src/main/java/java/security/KeyStoreException.java
new file mode 100644
index 0000000..0e77e47
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/KeyStoreException.java
@@ -0,0 +1,62 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class KeyStoreException extends GeneralSecurityException {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = -1119353179322377262L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public KeyStoreException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public KeyStoreException() {
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public KeyStoreException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public KeyStoreException(Throwable cause) {
+        super(cause);
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/KeyStoreSpi.java b/libcore/security/src/main/java/java/security/KeyStoreSpi.java
new file mode 100644
index 0000000..0ed01dd
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/KeyStoreSpi.java
@@ -0,0 +1,271 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package java.security;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.util.Date;
+import java.util.Enumeration;
+import javax.crypto.SecretKey;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.PasswordCallback;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+public abstract class KeyStoreSpi {
+
+    public abstract Key engineGetKey(String alias, char[] password)
+            throws NoSuchAlgorithmException, UnrecoverableKeyException;
+
+    public abstract Certificate[] engineGetCertificateChain(String alias);
+
+    public abstract Certificate engineGetCertificate(String alias);
+
+    public abstract Date engineGetCreationDate(String alias);
+
+    public abstract void engineSetKeyEntry(String alias, Key key,
+            char[] password, Certificate[] chain) throws KeyStoreException;
+
+    public abstract void engineSetKeyEntry(String alias, byte[] key,
+            Certificate[] chain) throws KeyStoreException;
+
+    public abstract void engineSetCertificateEntry(String alias,
+            Certificate cert) throws KeyStoreException;
+
+    public abstract void engineDeleteEntry(String alias)
+            throws KeyStoreException;
+
+    public abstract Enumeration<String> engineAliases();
+
+    public abstract boolean engineContainsAlias(String alias);
+
+    public abstract int engineSize();
+
+    public abstract boolean engineIsKeyEntry(String alias);
+
+    public abstract boolean engineIsCertificateEntry(String alias);
+
+    public abstract String engineGetCertificateAlias(Certificate cert);
+
+    public abstract void engineStore(OutputStream stream, char[] password)
+            throws IOException, NoSuchAlgorithmException, CertificateException;
+
+    public void engineStore(KeyStore.LoadStoreParameter param)
+            throws IOException, NoSuchAlgorithmException, CertificateException {
+        throw new UnsupportedOperationException(Messages.getString("security.33")); //$NON-NLS-1$
+    }
+
+    public abstract void engineLoad(InputStream stream, char[] password)
+            throws IOException, NoSuchAlgorithmException, CertificateException;
+
+    public void engineLoad(KeyStore.LoadStoreParameter param)
+            throws IOException, NoSuchAlgorithmException, CertificateException {
+        if (param == null) {
+            engineLoad(null, null);
+            return;
+        }
+        char[] pwd;
+        KeyStore.ProtectionParameter pp = param.getProtectionParameter();
+        if (pp instanceof KeyStore.PasswordProtection) {
+            try {
+                pwd = ((KeyStore.PasswordProtection) pp).getPassword();
+                engineLoad(null, pwd);
+                return;
+            } catch (IllegalStateException e) {
+                throw new IllegalArgumentException(e);
+            }
+        }
+        if (pp instanceof KeyStore.CallbackHandlerProtection) {
+            try {
+                pwd = getPasswordFromCallBack(pp);
+                engineLoad(null, pwd);
+                return;
+            } catch (UnrecoverableEntryException e) {
+                throw new IllegalArgumentException(e);
+            }
+        }
+        throw new UnsupportedOperationException(
+                Messages.getString("security.35")); //$NON-NLS-1$
+    }
+
+    public KeyStore.Entry engineGetEntry(String alias,
+            KeyStore.ProtectionParameter protParam) throws KeyStoreException,
+            NoSuchAlgorithmException, UnrecoverableEntryException {
+        if (!engineContainsAlias(alias)) {
+            return null;
+        }
+        if (engineIsCertificateEntry(alias)) {
+            return new KeyStore.TrustedCertificateEntry(
+                    engineGetCertificate(alias));
+        }
+        char[] passW = null;
+        if (protParam != null) {
+            if (protParam instanceof KeyStore.PasswordProtection) {
+                try {
+                    passW = ((KeyStore.PasswordProtection) protParam)
+                            .getPassword();
+                } catch (IllegalStateException ee) {
+                    throw new KeyStoreException(Messages.getString("security.36"), ee); //$NON-NLS-1$
+                }
+            } else if (protParam instanceof KeyStore.CallbackHandlerProtection) {
+                passW = getPasswordFromCallBack(protParam);
+            } else {
+                throw new UnrecoverableEntryException(
+                        Messages.getString("security.37", //$NON-NLS-1$
+                                protParam.toString()));
+            }
+        }
+        if (engineIsKeyEntry(alias)) {
+            try {
+                Key key = engineGetKey(alias, passW);
+                if (key instanceof PrivateKey) {
+                    return new KeyStore.PrivateKeyEntry((PrivateKey) key,
+                            engineGetCertificateChain(alias));
+                }
+                if (key instanceof SecretKey) {
+                    return new KeyStore.SecretKeyEntry((SecretKey) key);
+                }
+            } catch (UnrecoverableKeyException e) {
+                throw new KeyStoreException(e);
+            }
+        }
+        throw new NoSuchAlgorithmException(Messages.getString("security.38")); //$NON-NLS-1$
+    }
+
+    public void engineSetEntry(String alias, KeyStore.Entry entry,
+            KeyStore.ProtectionParameter protParam) throws KeyStoreException {
+        if (entry == null) {
+            throw new KeyStoreException(Messages.getString("security.39")); //$NON-NLS-1$
+        }
+
+        if (engineContainsAlias(alias)) {
+            engineDeleteEntry(alias);
+        }
+
+        if (entry instanceof KeyStore.TrustedCertificateEntry) {
+            KeyStore.TrustedCertificateEntry trE = (KeyStore.TrustedCertificateEntry) entry;
+            engineSetCertificateEntry(alias, trE.getTrustedCertificate());
+            return;
+        }
+
+        char[] passW = null;
+        if (protParam instanceof KeyStore.PasswordProtection) {
+            try {
+                passW = ((KeyStore.PasswordProtection) protParam).getPassword();
+            } catch (IllegalStateException ee) {
+                throw new KeyStoreException(Messages.getString("security.36"), ee); //$NON-NLS-1$
+            }
+        } else {
+            if (protParam instanceof KeyStore.CallbackHandlerProtection) {
+                try {
+                    passW = getPasswordFromCallBack(protParam);
+                } catch (Exception e) {
+                    throw new KeyStoreException(e);
+                }
+            } else {
+                throw new KeyStoreException(
+                        Messages.getString("security.3A")); //$NON-NLS-1$
+            }
+        }
+
+        if (entry instanceof KeyStore.PrivateKeyEntry) {
+            KeyStore.PrivateKeyEntry prE = (KeyStore.PrivateKeyEntry) entry;
+            engineSetKeyEntry(alias, prE.getPrivateKey(), passW, prE
+                    .getCertificateChain());
+            return;
+        }
+
+        if (entry instanceof KeyStore.SecretKeyEntry) {
+            KeyStore.SecretKeyEntry skE = (KeyStore.SecretKeyEntry) entry;
+            engineSetKeyEntry(alias, skE.getSecretKey(), passW, null);
+            //            engineSetKeyEntry(alias, skE.getSecretKey().getEncoded(), null);
+            return;
+        }
+
+        throw new KeyStoreException(
+                Messages.getString("security.3B", entry.toString())); //$NON-NLS-1$
+    }
+
+    public boolean engineEntryInstanceOf(String alias,
+            Class<? extends KeyStore.Entry> entryClass) {
+        if (!engineContainsAlias(alias)) {
+            return false;
+        }
+
+        try {
+            if (engineIsCertificateEntry(alias)) {
+                return entryClass
+                        .isAssignableFrom(Class
+                                .forName("java.security.KeyStore$TrustedCertificateEntry")); //$NON-NLS-1$
+            }
+
+            if (engineIsKeyEntry(alias)) {
+                if (entryClass.isAssignableFrom(Class
+                        .forName("java.security.KeyStore$PrivateKeyEntry"))) { //$NON-NLS-1$
+                    return engineGetCertificate(alias) != null;
+                }
+
+                if (entryClass.isAssignableFrom(Class
+                        .forName("java.security.KeyStore$SecretKeyEntry"))) { //$NON-NLS-1$
+                    return engineGetCertificate(alias) == null;
+                }
+            }
+        } catch (ClassNotFoundException ignore) {}
+
+        return false;
+    }
+
+    /*
+     * This method returns password which is encapsulated in
+     * CallbackHandlerProtection object If there is no implementation of
+     * CallbackHandler then this method returns null
+     */
+    static char[] getPasswordFromCallBack(KeyStore.ProtectionParameter protParam)
+            throws UnrecoverableEntryException {
+
+        if (protParam == null) {
+            return null;
+        }
+
+        if (!(protParam instanceof KeyStore.CallbackHandlerProtection)) {
+            throw new UnrecoverableEntryException(
+                    Messages.getString("security.3C")); //$NON-NLS-1$
+        }
+
+        String clName = Security
+                .getProperty("auth.login.defaultCallbackHandler"); //$NON-NLS-1$
+        if (clName == null) {
+            throw new UnrecoverableEntryException(
+                    Messages.getString("security.3D")); //$NON-NLS-1$
+
+        }
+
+        try {
+            Class<?> cl = Class.forName(clName);
+            CallbackHandler cbHand = (CallbackHandler) cl.newInstance();
+            PasswordCallback[] pwCb = { new PasswordCallback("password: ", true) }; //$NON-NLS-1$
+            cbHand.handle(pwCb);
+            return pwCb[0].getPassword();
+        } catch (Exception e) {
+            throw new UnrecoverableEntryException(e.toString());
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/MessageDigest.java b/libcore/security/src/main/java/java/security/MessageDigest.java
new file mode 100644
index 0000000..c665c45
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/MessageDigest.java
@@ -0,0 +1,375 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris V. Kuznetsov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.nio.ByteBuffer;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public abstract class MessageDigest extends MessageDigestSpi {
+    
+    // The service name
+    private static final String SERVICE = "MessageDigest"; //$NON-NLS-1$
+
+    // Used to access common engine functionality
+    private static Engine engine = new Engine(SERVICE);
+
+    // The provider
+    private Provider provider;
+
+    // The algorithm.
+    private String algorithm;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected MessageDigest(String algorithm) {
+        this.algorithm = algorithm;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public static MessageDigest getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        if (algorithm == null) {
+            throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+        }
+        MessageDigest result;
+        synchronized (engine) {
+            engine.getInstance(algorithm, null);
+            if (engine.spi instanceof MessageDigest) {
+                result = (MessageDigest) engine.spi;
+                result.algorithm = algorithm;
+                result.provider = engine.provider;
+                return result;
+            } else {
+                result = new MessageDigestImpl((MessageDigestSpi) engine.spi,
+                        engine.provider, algorithm);
+                return result;
+            }
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public static MessageDigest getInstance(String algorithm, String provider)
+            throws NoSuchAlgorithmException, NoSuchProviderException {
+        if ((provider == null) || (provider.length() == 0)) {
+            throw new IllegalArgumentException(Messages.getString("security.02")); //$NON-NLS-1$
+        }
+        Provider p = Security.getProvider(provider);
+        if (p == null) {
+            throw new NoSuchProviderException(Messages.getString("security.03", provider)); //$NON-NLS-1$
+        }
+        return getInstance(algorithm, p);
+    }
+
+    /**
+     * Returns a new MessageDigest which is capable of running the algorithm
+     * described by the argument. The result will be an instance of a subclass
+     * of MessageDigest which implements that algorithm.
+     * 
+     * 
+     * @param algorithm
+     *            java.lang.String Name of the algorithm desired
+     * @param provider
+     *            Provider Provider which has to implement the algorithm
+     * @return MessageDigest a concrete implementation for the algorithm
+     *         desired.
+     * 
+     * @exception NoSuchAlgorithmException
+     *                If the algorithm cannot be found
+     */
+    public static MessageDigest getInstance(String algorithm, Provider provider)
+            throws NoSuchAlgorithmException {
+        if (provider == null) {
+            throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
+        }
+        if (algorithm == null) {
+            throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+        }
+        MessageDigest result;
+        synchronized (engine) {
+            engine.getInstance(algorithm, provider, null);
+            if (engine.spi instanceof MessageDigest) {
+                result = (MessageDigest) engine.spi;
+                result.algorithm = algorithm;
+                result.provider = provider;
+                return result;
+            } else {
+                result = new MessageDigestImpl((MessageDigestSpi) engine.spi,
+                        provider, algorithm);
+                return result;
+            }
+        }
+    }
+
+    // BEGIN android-note
+    // Removed @see tag that didn't seem to actually refer to anything.
+    // END android-note
+    
+    /**
+     * Puts the receiver back in an initial state, such that it is ready to
+     * compute a new hash.
+     */
+    public void reset() {
+        engineReset();
+    }
+
+    /**
+     * Includes the argument in the hash value computed
+     * by the receiver.
+     *
+     * @param arg0 byte
+     *             the byte to feed to the hash algorithm
+     *
+     * @see #reset()
+     */
+    public void update(byte arg0) {
+        engineUpdate(arg0);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public void update(byte[] input, int offset, int len) {
+        if (input == null ||
+                // offset < 0 || len < 0 ||
+                // checks for negative values are commented out intentionally
+                // see HARMONY-1120 for details
+                (long) offset + (long) len > input.length) {
+            throw new IllegalArgumentException(Messages
+                    .getString("security.05")); //$NON-NLS-1$
+        }
+        engineUpdate(input, offset, len);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public void update(byte[] input) {
+        if (input == null) {
+            throw new NullPointerException(Messages.getString("security.06")); //$NON-NLS-1$
+        }
+        engineUpdate(input, 0, input.length);
+    }
+
+    /**
+     * Computes and returns the final hash value that the receiver represents.
+     * After the digest is computed the receiver is reset.
+     * 
+     * @return the hash the receiver computed
+     * 
+     * @see #reset
+     */
+    public byte[] digest() {
+        return engineDigest();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public int digest(byte[] buf, int offset, int len) throws DigestException {
+        if (buf == null ||
+                // offset < 0 || len < 0 ||
+                // checks for negative values are commented out intentionally
+                // see HARMONY-1148 for details
+                (long) offset + (long) len > buf.length) {
+            throw new IllegalArgumentException(Messages
+                    .getString("security.05")); //$NON-NLS-1$
+        }
+        return engineDigest(buf, offset, len);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public byte[] digest(byte[] input) {
+        update(input);
+        return digest();
+    }
+
+    /**
+     * Returns a string containing a concise, human-readable description of the
+     * receiver.
+     * 
+     * @return a printable representation for the receiver.
+     */
+    public String toString() {
+        return "MESSAGE DIGEST " + algorithm; //$NON-NLS-1$
+    }
+
+    /**
+     * Does a simply byte-per-byte compare of the two digests.
+     * 
+     * @param digesta
+     *            One of the digests to compare
+     * @param digestb
+     *            The digest to compare to
+     * 
+     * @return <code>true</code> if the two hashes are equal
+     *         <code>false</code> if the two hashes are not equal
+     */
+    public static boolean isEqual(byte[] digesta, byte[] digestb) {
+        if (digesta.length != digestb.length) {
+            return false;
+        }
+        for (int i = 0; i < digesta.length; i++) {
+            if (digesta[i] != digestb[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Returns the standard Java Security name for the algorithm being used by
+     * the receiver.
+     * 
+     * @return String the name of the algorithm
+     */
+    public final String getAlgorithm() {
+        return algorithm;
+    }
+
+    /**
+     * Returns the Provider of the digest represented by the receiver.
+     * 
+     * @return Provider an instance of a subclass of java.security.Provider
+     */
+    public final Provider getProvider() {
+        return provider;
+    }
+
+    /**
+     * Return the engine digest length in bytes. Default is 0.
+     * 
+     * @return int the engine digest length in bytes
+     * 
+     */
+    public final int getDigestLength() {
+        int l = engineGetDigestLength();
+        if (l != 0) {
+            return l;
+        }
+        if (!(this instanceof Cloneable)) {
+            return 0;
+        }
+        try {
+            MessageDigest md = (MessageDigest) clone();
+            return md.digest().length;
+        } catch (CloneNotSupportedException e) {
+            return 0;
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public Object clone() throws CloneNotSupportedException {
+        if (this instanceof Cloneable) {
+            return super.clone();
+        } else {
+            throw new CloneNotSupportedException();
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final void update(ByteBuffer input) {
+        engineUpdate(input);
+    }
+
+    /**
+     * 
+     * The internal MessageDigest implementation
+     * 
+     */
+    private static class MessageDigestImpl extends MessageDigest {
+        
+        // MessageDigestSpi implementation
+        private MessageDigestSpi spiImpl;
+
+        // MessageDigestImpl ctor
+        private MessageDigestImpl(MessageDigestSpi messageDigestSpi,
+                Provider provider, String algorithm) {
+            super(algorithm);
+            super.provider = provider;
+            spiImpl = messageDigestSpi;
+        }
+
+        // engineReset() implementation
+        protected void engineReset() {
+            spiImpl.engineReset();
+        }
+
+        // engineDigest() implementation
+        protected byte[] engineDigest() {
+            return spiImpl.engineDigest();
+        }
+
+        // engineGetDigestLength() implementation
+        protected int engineGetDigestLength() {
+            return spiImpl.engineGetDigestLength();
+        }
+
+        // engineUpdate() implementation
+        protected void engineUpdate(byte arg0) {
+            spiImpl.engineUpdate(arg0);
+        }
+
+        // engineUpdate() implementation
+        protected void engineUpdate(byte[] arg0, int arg1, int arg2) {
+            spiImpl.engineUpdate(arg0, arg1, arg2);
+        }
+
+        // Returns a clone if the spiImpl is cloneable
+        public Object clone() throws CloneNotSupportedException {
+            if (spiImpl instanceof Cloneable) {
+                MessageDigestSpi spi = (MessageDigestSpi) spiImpl.clone();
+                return new MessageDigestImpl(spi, getProvider(), getAlgorithm());
+            } else {
+                throw new CloneNotSupportedException();
+            }
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/MessageDigestSpi.java b/libcore/security/src/main/java/java/security/MessageDigestSpi.java
new file mode 100644
index 0000000..3d44fb1
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/MessageDigestSpi.java
@@ -0,0 +1,129 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris V. Kuznetsov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.nio.ByteBuffer;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * This class is a Service Provider Interface (therefore the Spi suffix) for
+ * digest algorithms to be supplied by providers. Examples of digest algorithms
+ * are MD5 and SHA.
+ * 
+ * A digest is a secure hash function for a stream of bytes, like a fingerprint
+ * for the stream of bytes.
+ * 
+ */
+public abstract class MessageDigestSpi {
+    
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    protected int engineGetDigestLength() {
+        return 0;
+    }
+    
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    protected abstract void engineUpdate(byte input);
+    
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    protected abstract void engineUpdate(byte[] input, int offset, int len);
+    
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    protected void engineUpdate(ByteBuffer input) {
+        if (!input.hasRemaining()) {
+            return;
+        }
+        byte[] tmp;
+        if (input.hasArray()) {
+            tmp = input.array();
+            int offset = input.arrayOffset();
+            int position = input.position();
+            int limit = input.limit();
+            engineUpdate(tmp, offset+position, limit - position);
+            input.position(limit);
+        } else {
+            tmp = new byte[input.limit() - input.position()];
+            input.get(tmp);
+            engineUpdate(tmp, 0, tmp.length);
+        }    
+    }
+    
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    protected abstract byte[] engineDigest();
+    
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    protected int engineDigest(byte[] buf, int offset, int len)
+                    throws DigestException {
+        if (len < engineGetDigestLength()) {
+            engineReset();
+            throw new DigestException(Messages.getString("security.1B"));  //$NON-NLS-1$
+        }
+        if (offset < 0) {
+            engineReset();
+            throw new DigestException(Messages.getString("security.1C")); //$NON-NLS-1$
+        }
+        if (offset + len > buf.length) {
+            engineReset();
+            throw new DigestException(Messages.getString("security.1D")); //$NON-NLS-1$
+        }
+        byte tmp[] = engineDigest();
+        if (len < tmp.length) {
+            throw new DigestException(Messages.getString("security.1B")); //$NON-NLS-1$
+        }
+        System.arraycopy(tmp, 0, buf, offset, tmp.length);
+        return tmp.length;            
+    }
+    
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    protected abstract void engineReset();
+    
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    public Object clone() throws CloneNotSupportedException {
+        return super.clone();
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/NoSuchAlgorithmException.java b/libcore/security/src/main/java/java/security/NoSuchAlgorithmException.java
new file mode 100644
index 0000000..98650c2
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/NoSuchAlgorithmException.java
@@ -0,0 +1,70 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * Instances of this class are thrown when an attempt is made to access an
+ * algorithm which is not provided by the library.
+ * 
+ * @see Throwable
+ */
+public class NoSuchAlgorithmException extends GeneralSecurityException {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = -7443947487218346562L;
+
+    /**
+     * Constructs a new instance of this class with its walkback and message
+     * filled in.
+     * 
+     * 
+     * @param msg
+     *            String The detail message for the exception.
+     */
+    public NoSuchAlgorithmException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a new instance of this class with its walkback filled in.
+     * 
+     */
+    public NoSuchAlgorithmException() {
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public NoSuchAlgorithmException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public NoSuchAlgorithmException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/NoSuchProviderException.java b/libcore/security/src/main/java/java/security/NoSuchProviderException.java
new file mode 100644
index 0000000..5710916
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/NoSuchProviderException.java
@@ -0,0 +1,55 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * Instances of this class are thrown when an attempt is made to access a
+ * provider by name which is not currently available.
+ * 
+ * 
+ * @see Throwable
+ */
+public class NoSuchProviderException extends GeneralSecurityException {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = 8488111756688534474L;
+
+    /**
+     * Constructs a new instance of this class with its walkback and message
+     * filled in.
+     * 
+     * @param msg
+     *            String The detail message for the exception.
+     */
+    public NoSuchProviderException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a new instance of this class with its walkback filled in.
+     * 
+     */
+    public NoSuchProviderException() {
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/Permission.java b/libcore/security/src/main/java/java/security/Permission.java
new file mode 100644
index 0000000..de91fc4
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/Permission.java
@@ -0,0 +1,136 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.Serializable;
+
+/**
+ * Abstract superclass of all classes which represent permission to access
+ * system resources.
+ * 
+ */
+public abstract class Permission implements Guard, Serializable {
+
+    /** 
+     * @com.intel.drl.spec_ref 
+     */
+    private static final long serialVersionUID = -5636570222231596674L;
+
+    private final String name;
+
+    /** 
+     * @com.intel.drl.spec_ref 
+     */
+    public abstract boolean equals(Object obj);
+
+    /**
+     * Returns an integer hash code for the receiver. Any two objects which
+     * answer <code>true</code> when passed to <code>.equals</code> must
+     * answer the same value for this method.
+     * 
+     * 
+     * @return int the receiver's hash.
+     * 
+     * @see #equals
+     */
+    public abstract int hashCode();
+
+    /**
+     * Returns the actions associated with the receiver. Subclasses should
+     * return their actions in canonical form. If no actions are associated with
+     * the receiver, the empty string should be returned.
+     * 
+     * 
+     * @return String the receiver's actions.
+     */
+    public abstract String getActions();
+
+    /**
+     * Indicates whether the argument permission is implied by the receiver.
+     * 
+     * 
+     * @return boolean <code>true</code> if the argument permission is implied
+     *         by the receiver, and <code>false</code> if it is not.
+     * @param permission
+     *            Permission the permission to check.
+     */
+    public abstract boolean implies(Permission permission);
+
+    /**
+     * Constructs a new instance of this class with its name set to the
+     * argument.
+     * 
+     * 
+     * @param name
+     *            String the name of the permission.
+     */
+    public Permission(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Returns the name of the receiver.
+     * 
+     * 
+     * @return String the receiver's name.
+     */
+    public final String getName() {
+        return name;
+    }
+
+    /** 
+     * @com.intel.drl.spec_ref 
+     */
+    public void checkGuard(Object obj) throws SecurityException {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(this);
+        }
+    }
+
+    /**
+     * Returns a new PermissionCollection for holding permissions of this class.
+     * Answer null if any permission collection can be used.
+     * 
+     * 
+     * @return PermissionCollection or null a suitable permission collection for
+     *         instances of the class of the receiver.
+     */
+    public PermissionCollection newPermissionCollection() {
+        return null;
+    }
+
+    /**
+     * Returns a string containing a concise, human-readable description of the
+     * receiver.
+     * 
+     * 
+     * @return String a printable representation for the receiver.
+     */
+    public String toString() {
+        String actions = getActions();
+        actions = (actions == null || actions.length() == 0) ? "" : " " //$NON-NLS-1$ //$NON-NLS-2$
+                + getActions();
+        return "(" + getClass().getName() + " " + getName() + actions + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/PermissionCollection.java b/libcore/security/src/main/java/java/security/PermissionCollection.java
new file mode 100644
index 0000000..a0cda25
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/PermissionCollection.java
@@ -0,0 +1,129 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+/**
+ * Abstract superclass of classes which are collections of Permission objects.
+ * 
+ */
+public abstract class PermissionCollection implements Serializable {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = -6727011328946861783L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private boolean readOnly; // = false;
+
+    /**
+     * Adds the argument to the collection.
+     * 
+     * 
+     * @param permission
+     *            java.security.Permission the permission to add to the
+     *            collection.
+     * @exception IllegalStateException
+     *                if the collection is read only.
+     */
+    public abstract void add(Permission permission);
+
+    /**
+     * Returns an enumeration of the permissions in the receiver.
+     * 
+     * 
+     * @return Enumeration the permissions in the receiver.
+     */
+    public abstract Enumeration<Permission> elements();
+
+    /**
+     * Indicates whether the argument permission is implied by the permissions
+     * contained in the receiver.
+     * 
+     * 
+     * @return boolean <code>true</code> if the argument permission is implied
+     *         by the permissions in the receiver, and <code>false</code> if
+     *         it is not.
+     * @param permission
+     *            java.security.Permission the permission to check
+     */
+    public abstract boolean implies(Permission permission);
+
+    /**
+     * Indicates whether new permissions can be added to the receiver.
+     * 
+     * 
+     * @return boolean <code>true</code> if the receiver is read only
+     *         <code>false</code> if new elements can still be added to the
+     *         receiver.
+     */
+    public boolean isReadOnly() {
+        return readOnly;
+    }
+
+    /**
+     * Marks the receiver as read only, so that no new permissions can be added
+     * to it.
+     * 
+     */
+    public void setReadOnly() {
+        readOnly = true;
+    }
+
+    /**
+     * Returns a string containing a concise, human-readable description of the
+     * receiver.
+     * 
+     * 
+     * @return a printable representation for the receiver.
+     */
+    public String toString() {
+        List elist = new ArrayList(100);
+        Enumeration elenum = elements();
+        String superStr = super.toString();
+        int totalLength = superStr.length() + 5;
+        if (elenum != null) {
+            while (elenum.hasMoreElements()) {
+                String el = elenum.nextElement().toString();
+                totalLength += el.length();
+                elist.add(el);
+            }
+        }
+        int esize = elist.size();
+        totalLength += esize * 4;
+        //FIXME StringBuffer --> StringBuilder
+        StringBuffer result = new StringBuffer(totalLength).append(superStr)
+            .append(" ("); //$NON-NLS-1$
+        for (int i = 0; i < esize; i++) {
+            result.append("\n  ").append(elist.get(i).toString()); //$NON-NLS-1$
+        }
+        return result.append("\n)").toString(); //$NON-NLS-1$
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/Permissions.java b/libcore/security/src/main/java/java/security/Permissions.java
new file mode 100644
index 0000000..93faf33
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/Permissions.java
@@ -0,0 +1,262 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.io.Serializable;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * A heterogeneous collection of permissions.
+ * 
+ */
+public final class Permissions extends PermissionCollection implements
+    Serializable {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = 4858622370623524688L;
+
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("perms", Hashtable.class), //$NON-NLS-1$
+        new ObjectStreamField("allPermission", PermissionCollection.class), }; //$NON-NLS-1$
+
+    // Hash to store PermissionCollection's
+    private transient Map klasses = new HashMap();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private boolean allEnabled;  // = false;
+
+    /**
+     * Adds the argument to the collection.
+     * 
+     * 
+     * @param permission
+     *            java.security.Permission the permission to add to the
+     *            collection
+     */
+    public void add(Permission permission) {
+        if (isReadOnly()) {
+            throw new SecurityException(Messages.getString("security.15")); //$NON-NLS-1$
+        }
+
+        if (permission == null) {
+            throw new NullPointerException(Messages.getString("security.20")); //$NON-NLS-1$
+        }
+
+        Class klass = permission.getClass();
+        PermissionCollection klassMates = (PermissionCollection)klasses
+            .get(klass);
+
+        if (klassMates == null) {
+            synchronized (klasses) {
+                klassMates = (PermissionCollection)klasses.get(klass);
+                if (klassMates == null) {
+
+                    klassMates = permission.newPermissionCollection();
+                    if (klassMates == null) {
+                        klassMates = new PermissionsHash();
+                    }
+                    klasses.put(klass, klassMates);
+                }
+            }
+        }
+        klassMates.add(permission);
+
+        if (klass == AllPermission.class) {
+            allEnabled = true;
+        }
+    }
+
+    /**
+     * Returns an enumeration of the permissions in the receiver.
+     * 
+     * 
+     * @return Enumeration the permissions in the receiver.
+     */
+    public Enumeration<Permission> elements() {
+        return new MetaEnumeration(klasses.values().iterator());
+    }
+
+    /**
+     * An auxiliary implementation for enumerating individual permissions from a
+     * collection of PermissionCollections.
+     * 
+     */
+    final static class MetaEnumeration implements Enumeration {
+
+        private Iterator pcIter;
+
+        private Enumeration current;
+
+        /**
+         * Initiates this enumeration.
+         * 
+         * @param outer an iterator over external collection of
+         *        PermissionCollections
+         */
+        public MetaEnumeration(Iterator outer) {
+            pcIter = outer;
+            current = getNextEnumeration();
+        }
+
+        private Enumeration getNextEnumeration() {
+            while (pcIter.hasNext()) {
+                Enumeration en = ((PermissionCollection)pcIter.next())
+                    .elements();
+                if (en.hasMoreElements()) {
+                    return en;
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Indicates if there are more elements to enumerate.
+         */
+        public boolean hasMoreElements() {
+            return current != null /* && current.hasMoreElements() */;
+        }
+
+        /**
+         * Returns next element.
+         */
+        public Object nextElement() {
+            if (current != null) {
+                //assert current.hasMoreElements();
+                Object next = current.nextElement();
+                if (!current.hasMoreElements()) {
+                    current = getNextEnumeration();
+                }
+
+                return next;
+            }
+            throw new NoSuchElementException(Messages.getString("security.17")); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Indicates whether the argument permission is implied by the permissions
+     * contained in the receiver.
+     * 
+     * 
+     * @return boolean <code>true</code> if the argument permission is implied
+     *         by the permissions in the receiver, and <code>false</code> if
+     *         it is not.
+     * @param permission
+     *            java.security.Permission the permission to check
+     */
+    public boolean implies(Permission permission) {
+        if (permission == null) {
+            // RI compatible
+            throw new NullPointerException(Messages.getString("security.21")); //$NON-NLS-1$
+        }
+        if (allEnabled) {
+            return true;
+        }
+        Class klass = permission.getClass();
+        PermissionCollection klassMates = null;
+
+        UnresolvedPermissionCollection billets = (UnresolvedPermissionCollection)klasses
+            .get(UnresolvedPermission.class);
+        if (billets != null && billets.hasUnresolved(permission)) {
+            // try to fill up klassMates with freshly resolved permissions
+            synchronized (klasses) {
+                klassMates = (PermissionCollection)klasses.get(klass);
+                try {
+                    klassMates = billets.resolveCollection(permission,
+                                                           klassMates);
+                } catch (Exception ignore) {
+                    //TODO log warning
+                    ignore.printStackTrace();
+                }
+
+                if (klassMates != null) {
+                    //maybe klassMates were just created
+                    // so put them into common map
+                    klasses.put(klass, klassMates);
+                    // very uncommon case, but not improbable one
+                    if (klass == AllPermission.class) {
+                        allEnabled = true;
+                    }
+                }
+            }
+        } else {
+            klassMates = (PermissionCollection)klasses.get(klass);
+        }
+
+        if (klassMates != null) {
+            return klassMates.implies(permission);
+        }
+        return false;
+    }
+
+    /**
+     * Reads the object from stream and checks for consistency.
+     */
+    private void readObject(java.io.ObjectInputStream in) throws IOException,
+        ClassNotFoundException {
+        ObjectInputStream.GetField fields = in.readFields();
+        Map perms = (Map)fields.get("perms", null); //$NON-NLS-1$
+        klasses = new HashMap();
+        synchronized (klasses) {
+            for (Iterator iter = perms.keySet().iterator(); iter.hasNext();) {
+                Class key = (Class)iter.next();
+                PermissionCollection pc = (PermissionCollection)perms.get(key);
+                if (key != pc.elements().nextElement().getClass()) {
+                    throw new InvalidObjectException(Messages.getString("security.22")); //$NON-NLS-1$
+                }
+                klasses.put(key, pc);
+            }
+        }
+        allEnabled = fields.get("allPermission", null) != null; //$NON-NLS-1$
+        if (allEnabled && !klasses.containsKey(AllPermission.class)) {
+            throw new InvalidObjectException(Messages.getString("security.23")); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Outputs fields via default mechanism.
+     */
+    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
+        ObjectOutputStream.PutField fields = out.putFields();
+        fields.put("perms", new Hashtable(klasses)); //$NON-NLS-1$
+        fields.put("allPermission", allEnabled ? klasses //$NON-NLS-1$
+            .get(AllPermission.class) : null);
+        out.writeFields();
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/PermissionsHash.java b/libcore/security/src/main/java/java/security/PermissionsHash.java
new file mode 100644
index 0000000..875abe4
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/PermissionsHash.java
@@ -0,0 +1,92 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * A default PermissionCollection implementation that uses a hashtable. Each
+ * hashtable entry stores a Permission object as both the key and the value.
+ * <br>
+ * This PermissionCollection is intended for storing &quot;neutral&quot;
+ * permissions which do not require special collection.
+ * 
+ */
+
+final class PermissionsHash extends PermissionCollection {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = -8491988220802933440L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private final Hashtable perms = new Hashtable();
+
+    /**
+     * Adds the argument to the collection.
+     * 
+     * 
+     * @param permission
+     *            java.security.Permission the permission to add to the
+     *            collection
+     */
+    public void add(Permission permission) {
+        perms.put(permission, permission);
+    }
+
+    /**
+     * Returns an enumeration of the permissions in the receiver.
+     * 
+     * 
+     * @return Enumeration the permissions in the receiver.
+     */
+    public Enumeration elements() {
+        return perms.elements();
+    }
+
+    /**
+     * Indicates whether the argument permission is implied by the permissions
+     * contained in the receiver.
+     * 
+     * 
+     * @return boolean <code>true</code> if the argument permission is implied
+     *         by the permissions in the receiver, and <code>false</code> if
+     *         it is not.
+     * @param permission
+     *            java.security.Permission the permission to check
+     */
+    public boolean implies(Permission permission) {
+        for (Enumeration elements = elements(); elements.hasMoreElements();) {
+            if (((Permission)elements.nextElement()).implies(permission)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/Policy.java b/libcore/security/src/main/java/java/security/Policy.java
new file mode 100644
index 0000000..9198bde
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/Policy.java
@@ -0,0 +1,215 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.util.Enumeration;
+
+import org.apache.harmony.security.fortress.DefaultPolicy;
+import org.apache.harmony.security.fortress.PolicyUtils;
+
+
+/**
+ * Abstract superclass of classes which represent the system security policy.
+ * 
+ */
+public abstract class Policy {
+    
+    // Key to security properties, defining default policy provider.
+    private static final String POLICY_PROVIDER = "policy.provider"; //$NON-NLS-1$
+
+    // The SecurityPermission required to set custom Policy.
+    private static final SecurityPermission SET_POLICY = new SecurityPermission(
+            "setPolicy"); //$NON-NLS-1$
+
+    // The SecurityPermission required to get current Policy.
+    private static final SecurityPermission GET_POLICY = new SecurityPermission(
+            "getPolicy"); //$NON-NLS-1$
+
+    // The policy currently in effect. 
+    private static Policy activePolicy;
+
+    /**
+     * Returns a PermissionCollection describing what permissions are available
+     * to the given CodeSource based on the current security policy.
+     * <p>
+     * Note that this method is <em>not</em> called for classes which are in
+     * the system domain (i.e. system classes). System classes are
+     * <em>always</em> given full permissions (i.e. AllPermission). This can
+     * not be changed by installing a new Policy.
+     * 
+     * 
+     * @param cs
+     *            CodeSource the code source to compute the permissions for.
+     * @return PermissionCollection the permissions the code source should have.
+     */
+    public abstract PermissionCollection getPermissions(CodeSource cs);
+
+    /**
+     * Reloads the policy configuration, depending on how the type of source
+     * location for the policy information.
+     * 
+     * 
+     */
+    public abstract void refresh();
+
+    /**
+     * Returns a PermissionCollection describing what permissions are available
+     * to the given ProtectionDomain (more specifically, its CodeSource) based
+     * on the current security policy.
+     * 
+     * @param domain
+     *            ProtectionDomain the protection domain to compute the
+     *            permissions for.
+     * @return PermissionCollection the permissions the code source should have.
+     */
+    public PermissionCollection getPermissions(ProtectionDomain domain) {
+        if (domain != null) {
+            return getPermissions(domain.getCodeSource());
+        }
+        return new Permissions();
+    }
+
+    /**
+     * Returns whether the Permission is implied by the PermissionCollection of
+     * the Protection Domain
+     * 
+     * @param domain
+     *            ProtectionDomain for which Permission to be checked
+     * @param permission
+     *            Permission for which authorization is to be verified
+     * @return boolean Permission implied by ProtectionDomain
+     */
+    public boolean implies(ProtectionDomain domain, Permission permission) {
+        if (domain != null) {
+            PermissionCollection total = getPermissions(domain);
+            PermissionCollection inherent = domain.getPermissions();
+            if (total == null) {
+                total = inherent;
+            } else if (inherent != null) {
+                for (Enumeration en = inherent.elements(); en.hasMoreElements();) {
+                    total.add((Permission)en.nextElement());
+                }
+            }
+            if (total != null && total.implies(permission)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the current system security policy. If no policy has been
+     * instantiated then this is done using the security property <EM>policy.provider</EM>
+     * 
+     * 
+     * @return Policy the current system security policy.
+     */
+    public static Policy getPolicy() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(GET_POLICY);
+        }
+        return getAccessiblePolicy();
+    }
+
+     // Reads name of default policy provider from security.properties,
+     // loads the class and instantiates the provider.<br> 
+     // In case of any error, including undefined provider name, 
+     // returns new instance of org.apache.harmony.security.FilePolicy provider. 
+    private static Policy getDefaultProvider() {
+        final String defaultClass = (String) AccessController
+                .doPrivileged(new PolicyUtils.SecurityPropertyAccessor(
+                        POLICY_PROVIDER));
+        if (defaultClass == null) {
+            //TODO log warning
+            //System.err.println("No policy provider specified. Loading the " 
+            //           + DefaultPolicy.class.getName());
+            return new DefaultPolicy();
+        }
+
+        // TODO accurate classloading
+        return AccessController.doPrivileged(new PrivilegedAction<Policy>() {
+
+            public Policy run() {
+                try {
+                    return (Policy) Class.forName(defaultClass, true,
+                            ClassLoader.getSystemClassLoader()).newInstance();
+                }
+                catch (Exception e) {
+                    //TODO log error 
+                    //System.err.println("Error loading policy provider <" 
+                    //                 + defaultClass + "> : " + e 
+                    //                 + "\nSwitching to the default " 
+                    //                 + DefaultPolicy.class.getName());
+                    return new DefaultPolicy();
+                }
+            }
+        });
+
+    }
+    
+    /**
+     * Returns true if system policy provider is instantiated.
+     */
+    static boolean isSet() {
+        return activePolicy != null;
+    }
+
+    /**
+     * Shortcut accessor for friendly classes, to skip security checks.
+     * If active policy was set to <code>null</code>, loads default provider, 
+     * so this method never returns <code>null</code>. <br>
+     * This method is synchronized with setPolicy()
+     */
+    static Policy getAccessiblePolicy() {
+        Policy current = activePolicy;
+        if (current == null) {
+            synchronized (Policy.class) {
+                // double check in case value has been reassigned 
+                // while we've been awaiting monitor
+                if (activePolicy == null) {
+                    activePolicy = getDefaultProvider();
+                }
+                return activePolicy;
+            }
+        }
+        return current;
+    }
+
+    /**
+     * Sets the system-wide policy object if it is permitted by the security
+     * manager.
+     * 
+     * @param policy
+     *            Policy the policy object that needs to be set.
+     */
+    public static void setPolicy(Policy policy) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(SET_POLICY);
+        }
+        synchronized (Policy.class) {
+            activePolicy = policy;
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/Principal.java b/libcore/security/src/main/java/java/security/Principal.java
new file mode 100644
index 0000000..2fac7af
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/Principal.java
@@ -0,0 +1,48 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Astapchuk
+* @version $Revision$
+*/
+
+package java.security;
+
+
+/**
+ * Principals are objects which have identities. These can be individuals,
+ * groups, corporations, unique program executions, etc.
+ * 
+ */
+public interface Principal {
+    /** 
+     * @com.intel.drl.spec_ref 
+     */
+    public boolean equals( Object obj );
+    /** 
+     * @com.intel.drl.spec_ref 
+     */
+    public String getName();
+    /** 
+     * @com.intel.drl.spec_ref 
+     */
+    public int hashCode();
+    /** 
+     * @com.intel.drl.spec_ref 
+     */
+    public String toString();
+}
diff --git a/libcore/security/src/main/java/java/security/PrivateKey.java b/libcore/security/src/main/java/java/security/PrivateKey.java
new file mode 100644
index 0000000..f09b4a8
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/PrivateKey.java
@@ -0,0 +1,34 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface PrivateKey extends Key {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public static final long serialVersionUID = 6034044314589513430L;
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/PrivilegedAction.java b/libcore/security/src/main/java/java/security/PrivilegedAction.java
new file mode 100644
index 0000000..4e16e3a
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/PrivilegedAction.java
@@ -0,0 +1,34 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Astapchuk
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * @com.intel.drl.spec_ref 
+ */
+
+public interface PrivilegedAction<T> {
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public T run();
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/PrivilegedActionException.java b/libcore/security/src/main/java/java/security/PrivilegedActionException.java
new file mode 100644
index 0000000..d68b6b9
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/PrivilegedActionException.java
@@ -0,0 +1,82 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Astapchuk
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * Instances of this class are used to wrap exceptions which occur within
+ * privileged operations.
+ * 
+ */
+public class PrivilegedActionException extends Exception {
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    private static final long serialVersionUID = 4724086851538908602l;
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    private Exception exception;
+
+    /**
+     * Constructs a new instance of this class with its exception filled in.
+     * @param ex 
+     */
+    public PrivilegedActionException(Exception ex) {
+        super(ex);
+        this.exception = ex;
+    }
+
+    /**
+     * Returns the exception which caused the receiver to be thrown.
+     * @return exception
+     */
+    public Exception getException() {
+        return exception; // return ( getCause() instanceof Exception ) ?
+        // getCause() : null;
+    }
+
+    /**
+     * Returns the cause of this Throwable, or null if there is no cause.
+     * 
+     * 
+     * @return Throwable The receiver's cause.
+     */
+    public Throwable getCause() {
+        return exception;
+    }
+
+    /**
+     * Returns a string containing a concise, human-readable description of the
+     * receiver.
+     * 
+     * 
+     * @return String a printable representation for the receiver.
+     */
+    public String toString() {
+        String s = getClass().getName();
+        return exception == null ? s : s + ": " + exception; //$NON-NLS-1$
+    }
+
+}
diff --git a/libcore/security/src/main/java/java/security/PrivilegedExceptionAction.java b/libcore/security/src/main/java/java/security/PrivilegedExceptionAction.java
new file mode 100644
index 0000000..98d56e3
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/PrivilegedExceptionAction.java
@@ -0,0 +1,33 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Astapchuk
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * @com.intel.drl.spec_ref
+ */
+public interface PrivilegedExceptionAction<T> {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    T run() throws Exception;
+}
diff --git a/libcore/security/src/main/java/java/security/ProtectionDomain.java b/libcore/security/src/main/java/java/security/ProtectionDomain.java
new file mode 100644
index 0000000..6f98194
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/ProtectionDomain.java
@@ -0,0 +1,224 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Astapchuk
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * This class represents a domain in which classes from the same source (URL)
+ * and signed by the same keys are stored. All the classes inside are given the
+ * same permissions.
+ * <p>
+ * Note: a class can only belong to one and only one protection domain.
+ */
+public class ProtectionDomain {
+
+    // CodeSource for this ProtectionDomain
+    private CodeSource codeSource;
+
+    // Static permissions for this ProtectionDomain
+    private PermissionCollection permissions;
+
+    // ClassLoader
+    private ClassLoader classLoader;
+
+    // Set of principals associated with this ProtectionDomain
+    private Principal[] principals;
+
+    // false if this ProtectionDomain was constructed with static 
+    // permissions, true otherwise. 
+    private boolean dynamicPerms;
+
+    /**
+     * Constructs a protection domain from the given code source and the
+     * permissions that that should be granted to the classes which are
+     * encapsulated in it.
+     * @param cs 
+     * @param permissions 
+     */
+    public ProtectionDomain(CodeSource cs, PermissionCollection permissions) {
+        this.codeSource = cs;
+        if (permissions != null) {
+            permissions.setReadOnly();
+        }
+        this.permissions = permissions;
+        //this.classLoader = null;
+        //this.principals = null;
+        //dynamicPerms = false;
+    }
+
+    /**
+     * Constructs a protection domain from the given code source and the
+     * permissions that that should be granted to the classes which are
+     * encapsulated in it. 
+     * 
+     * This constructor also allows the association of a ClassLoader and group
+     * of Principals.
+     * 
+     * @param cs
+     *            the CodeSource associated with this domain
+     * @param permissions
+     *            the Permissions associated with this domain
+     * @param cl
+     *            the ClassLoader associated with this domain
+     * @param principals
+     *            the Principals associated with this domain
+     */
+    public ProtectionDomain(CodeSource cs, PermissionCollection permissions,
+            ClassLoader cl, Principal[] principals) {
+        this.codeSource = cs;
+        if (permissions != null) {
+            permissions.setReadOnly();
+        }
+        this.permissions = permissions;
+        this.classLoader = cl;
+        if (principals != null) {
+            this.principals = new Principal[principals.length];
+            System.arraycopy(principals, 0, this.principals, 0,
+                    this.principals.length);
+        }
+        dynamicPerms = true;
+    }
+
+    /**
+     * Returns the ClassLoader associated with the ProtectionDomain
+     * 
+     * @return ClassLoader associated ClassLoader
+     */
+    public final ClassLoader getClassLoader() {
+        return classLoader;
+    }
+
+    /**
+     * Returns the code source of this domain.
+     * 
+     * @return java.security.CodeSource the code source of this domain
+     */
+    public final CodeSource getCodeSource() {
+        return codeSource;
+    }
+
+    /**
+     * Returns the permissions that should be granted to the classes which are
+     * encapsulated in this domain.
+     * 
+     * @return java.security.PermissionCollection collection of permissions
+     *         associated with this domain.
+     */
+    public final PermissionCollection getPermissions() {
+        return permissions;
+    }
+
+    /**
+     * Returns the Principals associated with this ProtectionDomain. A change to
+     * the returned array will not impact the ProtectionDomain.
+     * 
+     * @return Principals[] Principals associated with the ProtectionDomain.
+     */
+    public final Principal[] getPrincipals() {
+        if( principals == null ) {
+            return new Principal[0];
+        }
+        Principal[] tmp = new Principal[principals.length];
+        System.arraycopy(principals, 0, tmp, 0, tmp.length);
+        return tmp;
+    }
+
+    /**
+     * Determines whether the permission collection of this domain implies the
+     * argument permission.
+     * 
+     * 
+     * @return boolean true if this permission collection implies the argument
+     *         and false otherwise.
+     * @param permission
+     *            java.security.Permission the permission to check.
+     */
+    public boolean implies(Permission permission) {
+        // First, test with the Policy, as the default Policy.implies() 
+        // checks for both dynamic and static collections of the 
+        // ProtectionDomain passed...
+        if (dynamicPerms
+                && Policy.getAccessiblePolicy().implies(this, permission)) {
+            return true;
+        }
+
+        // ... and we get here if 
+        // either the permissions are static
+        // or Policy.implies() did not check for static permissions
+        // or the permission is not implied
+        return permissions == null ? false : permissions.implies(permission);
+    }
+
+    /**
+     * Returns a string containing a concise, human-readable description of the
+     * receiver.
+     * 
+     * @return String a printable representation for the receiver.
+     */
+    public String toString() {
+        //FIXME: 1.5 use StreamBuilder here
+        StringBuffer buf = new StringBuffer(200);
+        buf.append("ProtectionDomain\n"); //$NON-NLS-1$
+        buf.append("CodeSource=").append( //$NON-NLS-1$
+                codeSource == null ? "<null>" : codeSource.toString()).append( //$NON-NLS-1$
+                "\n"); //$NON-NLS-1$
+        buf.append("ClassLoader=").append( //$NON-NLS-1$
+                classLoader == null ? "<null>" : classLoader.toString()) //$NON-NLS-1$
+                .append("\n"); //$NON-NLS-1$
+        if (principals == null || principals.length == 0) {
+            buf.append("<no principals>\n"); //$NON-NLS-1$
+        } else {
+            buf.append("Principals: <\n"); //$NON-NLS-1$
+            for (int i = 0; i < principals.length; i++) {
+                buf.append("\t").append( //$NON-NLS-1$
+                        principals[i] == null ? "<null>" : principals[i] //$NON-NLS-1$
+                                .toString()).append("\n"); //$NON-NLS-1$
+            }
+            buf.append(">"); //$NON-NLS-1$
+        }
+
+        //permissions here
+        buf.append("Permissions:\n"); //$NON-NLS-1$
+        if (permissions == null) {
+            buf.append("\t\t<no static permissions>\n"); //$NON-NLS-1$
+        } else {
+            buf.append("\t\tstatic: ").append(permissions.toString()).append( //$NON-NLS-1$
+                    "\n"); //$NON-NLS-1$
+        }
+
+        if (dynamicPerms) {
+            if (Policy.isSet()) {
+                PermissionCollection perms;
+                perms = Policy.getAccessiblePolicy().getPermissions(this);
+                if (perms == null) {
+                    buf.append("\t\t<no dynamic permissions>\n"); //$NON-NLS-1$
+                } else {
+                    buf.append("\t\tdynamic: ").append(perms.toString()) //$NON-NLS-1$
+                            .append("\n"); //$NON-NLS-1$
+                }
+            } else {
+                buf.append("\t\t<no dynamic permissions>\n"); //$NON-NLS-1$
+            }
+        }
+        return buf.toString();
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/Provider.java b/libcore/security/src/main/java/java/security/Provider.java
new file mode 100644
index 0000000..ae4acb9
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/Provider.java
@@ -0,0 +1,940 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris V. Kuznetsov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.harmony.luni.util.TwoKeyHashMap;
+import org.apache.harmony.security.fortress.Services;
+import org.apache.harmony.security.internal.nls.Messages;
+
+public abstract class Provider extends Properties {
+    private static final long serialVersionUID = -4298000515446427739L;
+
+    private String name;
+
+    private double version;
+
+    // String representation of the provider version number.
+    private transient String versionString;
+
+    private String info;
+
+    //The provider preference order number. 
+    // Equals -1 for non registered provider.
+    private transient int providerNumber = -1;
+
+    // Contains "Service.Algorithm" and Provider.Service classes added using
+    // putService()
+    private transient TwoKeyHashMap<String, String, Service> serviceTable;
+
+    // Contains "Service.Alias" and Provider.Service classes added using
+    // putService()
+    private transient TwoKeyHashMap<String, String, Service> aliasTable;
+
+    // Contains "Service.Algorithm" and Provider.Service classes added using
+    // put()
+    private transient TwoKeyHashMap<String, String, Service> propertyServiceTable;
+
+    // Contains "Service.Alias" and Provider.Service classes added using put()
+    private transient TwoKeyHashMap<String, String, Service> propertyAliasTable;
+
+    // The properties changed via put()
+    private transient Properties changedProperties;
+
+    // For getService(String type, String algorithm) optimization:
+    // previous result
+    private transient Provider.Service returnedService;
+    // previous parameters
+    private transient String lastAlgorithm;
+    // last name
+    private transient String lastServiceName;
+
+    // For getServices() optimization:
+    private transient Set<Service> lastServicesSet;
+
+    // For getService(String type) optimization:
+    private transient String lastType;
+    // last Service found by type
+    private transient Provider.Service lastServicesByType;
+
+    protected Provider(String name, double version, String info) {
+        this.name = name;
+        this.version = version;
+        this.info = info;
+        versionString = String.valueOf(version);
+        putProviderInfo();
+    }
+
+    /**
+     * Returns the name of this provider.
+     * 
+     * 
+     * 
+     * @return String name of the provider
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns the version number for the services being provided
+     * 
+     * 
+     * 
+     * @return double version number for the services being provided
+     */
+    public double getVersion() {
+        return version;
+    }
+
+    /**
+     * Returns the generic information about the services being provided.
+     * 
+     * 
+     * 
+     * @return String generic description of the services being provided
+     */
+    public String getInfo() {
+        return info;
+    }
+
+    /**
+     * Returns a string containing a concise, human-readable description of the
+     * receiver.
+     * 
+     * 
+     * @return a printable representation for the receiver.
+     */
+    public String toString() {
+        return name + " version " + version; //$NON-NLS-1$
+    }
+
+    public synchronized void clear() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("clearProviderProperties." + name); //$NON-NLS-1$
+        }
+        super.clear();
+        if (serviceTable != null) {
+            serviceTable.clear();
+        }
+        if (propertyServiceTable != null) {
+            propertyServiceTable.clear();
+        }
+        if (aliasTable != null) {
+            aliasTable.clear();
+        }
+        if (propertyAliasTable != null) {
+            propertyAliasTable.clear();
+        }
+        // BEGIN android-changed
+        changedProperties = null;
+        // END android-changed
+        putProviderInfo();
+        if (providerNumber != -1) {
+            // if registered then refresh Services
+            Services.setNeedRefresh();
+        }
+        servicesChanged();
+    }
+
+    public synchronized void load(InputStream inStream) throws IOException {
+        Properties tmp = new Properties();
+        tmp.load(inStream);
+        myPutAll(tmp);
+    }
+
+    public synchronized void putAll(Map<?,?> t) {
+
+        // Implementation note:
+        // checkSecurityAccess method call is NOT specified
+        // Do it as in put(Object key, Object value).
+
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("putProviderProperty." + name); //$NON-NLS-1$
+        }
+        myPutAll(t);
+    }
+
+    private void myPutAll(Map<?,?> t) {
+        if (changedProperties == null) {
+            changedProperties = new Properties();
+        }
+        Iterator<? extends Map.Entry<?, ?>> it = t.entrySet().iterator();
+        Object key;
+        Object value;
+        while (it.hasNext()) {
+            Map.Entry<?, ?> entry = it.next();
+            key = entry.getKey();
+            if (key instanceof String && ((String) key).startsWith("Provider.")) { //$NON-NLS-1$
+                // Provider service type is reserved
+                continue;
+            }
+            value = entry.getValue();
+            super.put(key, value);
+            if (changedProperties.remove(key) == null) {
+                removeFromPropertyServiceTable(key);
+            }
+            changedProperties.put(key, value);
+        }
+        if (providerNumber != -1) {
+            // if registered then refresh Services
+            Services.setNeedRefresh();
+        }
+    }
+
+    public synchronized Set<Map.Entry<Object,Object>> entrySet() {
+        return Collections.unmodifiableSet(super.entrySet());
+    }
+
+    public Set<Object> keySet() {
+        return Collections.unmodifiableSet(super.keySet());
+    }
+
+    public Collection<Object> values() {
+        return Collections.unmodifiableCollection(super.values());
+    }
+
+    public synchronized Object put(Object key, Object value) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("putProviderProperty." + name); //$NON-NLS-1$
+        }
+        if (key instanceof String && ((String) key).startsWith("Provider.")) { //$NON-NLS-1$
+            // Provider service type is reserved
+            return null;
+        }
+        if (providerNumber != -1) {
+            // if registered then refresh Services
+            Services.setNeedRefresh();
+        }
+        if (changedProperties != null && changedProperties.remove(key) == null) {
+            removeFromPropertyServiceTable(key);
+        }
+        if (changedProperties == null) {
+            changedProperties = new Properties();
+        }
+        changedProperties.put(key, value);
+        return super.put(key, value);
+    }
+
+    public synchronized Object remove(Object key) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("removeProviderProperty." + name); //$NON-NLS-1$
+        }
+        if (key instanceof String && ((String) key).startsWith("Provider.")) { //$NON-NLS-1$
+            // Provider service type is reserved
+            return null;
+        }
+        if (providerNumber != -1) {
+            // if registered then refresh Services
+            Services.setNeedRefresh();
+        }
+        if (changedProperties != null && changedProperties.remove(key) == null) {
+            removeFromPropertyServiceTable(key);
+            // BEGIN android-added
+            if (changedProperties.size() == 0) {
+                changedProperties = null;
+            }
+            // END android-added
+        }
+        return super.remove(key);
+    }
+
+    /**
+     * 
+     * returns true if the provider implements the specified algorithm.  Caller must
+     * specify the cryptographic service and specify constraints via the
+     * attribute name the attribute value
+     * 
+     * @param serv
+     *            Crypto service
+     * @param alg
+     *            Algorithm or type
+     * @param attribute
+     *            The attribute name or null
+     * @param val
+     *            The attribute value
+     * @return
+     */
+    boolean implementsAlg(String serv, String alg, String attribute, String val) {
+        String servAlg = serv + "." + alg; //$NON-NLS-1$
+        String prop = getPropertyIgnoreCase(servAlg);
+        if (prop == null) {
+            alg = getPropertyIgnoreCase("Alg.Alias." + servAlg); //$NON-NLS-1$
+            if (alg != null) {
+                servAlg = serv + "." + alg; //$NON-NLS-1$
+                prop = getPropertyIgnoreCase(serv + "." + alg); //$NON-NLS-1$
+            }
+        }
+        if (prop != null) {
+            if (attribute == null) {
+                return true;
+            } else {
+                return checkAttribute(serv + "." + alg, attribute, val); //$NON-NLS-1$
+            }
+        }
+        return false;
+    }
+
+    // returns true if the implementation meets the constraint expressed by the
+    // specified attribute name/value pair.
+    private boolean checkAttribute(String servAlg, String attribute, String val) {
+        
+        String attributeValue = getPropertyIgnoreCase(servAlg + ' ' + attribute);
+        if (attributeValue != null) {
+            if (attribute.equalsIgnoreCase("KeySize")) { //$NON-NLS-1$
+// BEGIN android-changed
+                if (Integer.parseInt(attributeValue) >= Integer.parseInt(val)) {
+// END android-changed
+                    return true;
+                }
+            } else { // other attributes
+                if (attributeValue.equalsIgnoreCase(val)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 
+     * Set the provider preference order number.
+     * 
+     * @param n
+     */
+    void setProviderNumber(int n) {
+        providerNumber = n;
+    }
+
+    /**
+     * 
+     * Get the provider preference order number.
+     * 
+     * @return
+     */
+    int getProviderNumber() {
+        return providerNumber;
+    }
+
+    /**
+     * Get the service of the specified type
+     *  
+     */
+    synchronized Provider.Service getService(String type) {
+        updatePropertyServiceTable();
+        if (lastServicesByType != null && type.equals(lastType)) {
+            return lastServicesByType;
+        }
+        Provider.Service service;
+        for (Iterator<Service> it = getServices().iterator(); it.hasNext();) {
+            service = it.next();
+            if (type.equals(service.type)) {
+                lastType = type;
+                lastServicesByType = service;
+                return service;
+            }
+        }
+        return null;
+    }
+
+    public synchronized Provider.Service getService(String type,
+            String algorithm) {
+        if (type == null || algorithm == null) {
+            throw new NullPointerException();
+        }
+
+        if (type.equals(lastServiceName)
+                && algorithm.equalsIgnoreCase(lastAlgorithm)) {
+            return returnedService;
+        }
+
+        String alg = algorithm.toUpperCase();
+        Object o = null;
+        if (serviceTable != null) {
+            o = serviceTable.get(type, alg);
+        }
+        if (o == null && aliasTable != null) {
+            o = aliasTable.get(type, alg);
+        }
+        if (o == null) {
+            updatePropertyServiceTable();
+        }
+        if (o == null && propertyServiceTable != null) {
+            o = propertyServiceTable.get(type, alg);
+        }
+        if (o == null && propertyAliasTable != null) {
+            o = propertyAliasTable.get(type, alg);
+        }
+
+        if (o != null) {
+            lastServiceName = type;
+            lastAlgorithm = algorithm;
+            returnedService = (Provider.Service) o;
+            return returnedService;
+        }
+        return null;
+    }
+
+    public synchronized Set<Provider.Service> getServices() {
+        updatePropertyServiceTable();
+        if (lastServicesSet != null) {
+            return lastServicesSet;
+        }
+        if (serviceTable != null) {
+            lastServicesSet = new HashSet<Service>(serviceTable.values());
+        } else {
+            lastServicesSet = new HashSet<Service>();
+        }
+        if (propertyServiceTable != null) {
+            lastServicesSet.addAll(propertyServiceTable.values());
+        }
+        lastServicesSet = Collections.unmodifiableSet(lastServicesSet);
+        return lastServicesSet;
+    }
+
+    protected synchronized void putService(Provider.Service s) {
+        if (s == null) {
+            throw new NullPointerException();
+        }
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("putProviderProperty." + name); //$NON-NLS-1$
+        }
+        if ("Provider".equals(s.getType())) { // Provider service type cannot be //$NON-NLS-1$
+                                              // added
+            return;
+        }
+        servicesChanged();
+        if (serviceTable == null) {
+            serviceTable = new TwoKeyHashMap<String, String, Service>(128);
+        }
+        serviceTable.put(s.type, s.algorithm.toUpperCase(), s);
+        if (s.aliases != null) {
+            if (aliasTable == null) {
+                aliasTable = new TwoKeyHashMap<String, String, Service>(256);
+            }
+            for (Iterator<String> it = s.getAliases(); it.hasNext();) {
+                aliasTable.put(s.type, (it.next()).toUpperCase(), s);
+            }
+        }
+        serviceInfoToProperties(s);
+    }
+
+    protected synchronized void removeService(Provider.Service s) {
+        if (s == null) {
+            throw new NullPointerException();
+        }
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("removeProviderProperty." + name); //$NON-NLS-1$
+        }
+        servicesChanged();
+        if (serviceTable != null) {
+            serviceTable.remove(s.type, s.algorithm.toUpperCase());
+        }
+        if (aliasTable != null && s.aliases != null) {
+            for (Iterator<String> it = s.getAliases(); it.hasNext();) {
+                aliasTable.remove(s.type, (it.next()).toUpperCase());
+            }
+        }
+        serviceInfoFromProperties(s);
+    }
+
+    // Add Service information to the provider's properties.
+    private void serviceInfoToProperties(Provider.Service s) {
+        super.put(s.type + "." + s.algorithm, s.className); //$NON-NLS-1$
+        if (s.aliases != null) {
+            for (Iterator<String> i = s.aliases.iterator(); i.hasNext();) {
+                super.put("Alg.Alias." + s.type + "." + i.next(), s.algorithm); //$NON-NLS-1$ //$NON-NLS-2$
+            }
+        }
+        if (s.attributes != null) {
+            for (Iterator<Map.Entry<String, String>> i = s.attributes.entrySet().iterator(); i.hasNext();) {
+                Map.Entry<String, String> entry = i.next();
+                super.put(s.type + "." + s.algorithm + " " + entry.getKey(), //$NON-NLS-1$ //$NON-NLS-2$
+                        entry.getValue());
+            }
+        }
+        if (providerNumber != -1) {
+            // if registered then refresh Services
+            Services.setNeedRefresh();
+        }
+    }
+
+    // Remove Service information from the provider's properties.
+    private void serviceInfoFromProperties(Provider.Service s) {
+        super.remove(s.type + "." + s.algorithm); //$NON-NLS-1$
+        if (s.aliases != null) {
+            for (Iterator<String> i = s.aliases.iterator(); i.hasNext();) {
+                super.remove("Alg.Alias." + s.type + "." + i.next()); //$NON-NLS-1$ //$NON-NLS-2$
+            }
+        }
+        if (s.attributes != null) {
+            for (Iterator<Map.Entry<String, String>> i = s.attributes.entrySet().iterator(); i.hasNext();) {
+                Map.Entry<String, String> entry = i.next();
+                super.remove(s.type + "." + s.algorithm + " " + entry.getKey()); //$NON-NLS-1$ //$NON-NLS-2$
+            }
+        }
+        if (providerNumber != -1) {
+            // if registered then refresh Services
+            Services.setNeedRefresh();
+        }
+    }
+
+    // Remove property information from provider Services
+    private void removeFromPropertyServiceTable(Object key) {
+        if (key == null || !(key instanceof String)) {
+            return;
+        }
+        String k = (String) key;
+        if (k.startsWith("Provider.")) { // Provider service type is reserved //$NON-NLS-1$
+            return;
+        }
+        Provider.Service s;
+        String serviceName;
+        String algorithm = null;
+        String attribute = null;
+        int i;
+        if (k.startsWith("Alg.Alias.")) { // Alg.Alias.<crypto_service>.<aliasName>=<stanbdardName> //$NON-NLS-1$
+            String aliasName;
+            String service_alias = k.substring(10);
+            i = service_alias.indexOf("."); //$NON-NLS-1$
+            serviceName = service_alias.substring(0, i);
+            aliasName = service_alias.substring(i + 1);
+            if (propertyAliasTable != null) {
+                propertyAliasTable.remove(serviceName, aliasName.toUpperCase());
+            }
+            if (propertyServiceTable != null) {
+                for (Iterator<Service> it = propertyServiceTable.values().iterator(); it
+                        .hasNext();) {
+                    s = it.next();
+                    if (s.aliases.contains(aliasName)) {
+                        s.aliases.remove(aliasName);
+                        return;
+                    }
+                }
+            }
+            return;
+        }
+        int j = k.indexOf("."); //$NON-NLS-1$
+        if (j == -1) { // unknown format
+            return;
+        }
+
+        i = k.indexOf(" "); //$NON-NLS-1$
+        if (i == -1) { // <crypto_service>.<algorithm_or_type>=<className>
+            serviceName = k.substring(0, j);
+            algorithm = k.substring(j + 1);
+            if (propertyServiceTable != null) {
+                Provider.Service ser = propertyServiceTable.remove(serviceName, algorithm.toUpperCase());
+                if (ser != null && propertyAliasTable != null
+                        && ser.aliases != null) {
+                    for (Iterator<String> it = ser.aliases.iterator(); it.hasNext();) {
+                        propertyAliasTable.remove(serviceName, (it
+                                .next()).toUpperCase());
+                    }
+                }
+            }
+        } else { // <crypto_service>.<algorithm_or_type>
+                 // <attribute_name>=<attrValue>
+            attribute = k.substring(i + 1);
+            serviceName = k.substring(0, j);
+            algorithm = k.substring(j + 1, i);
+            if (propertyServiceTable != null) {
+                Object o = propertyServiceTable.get(serviceName, algorithm
+                        .toUpperCase());
+                if (o != null) {
+                    s = (Provider.Service) o;
+                    s.attributes.remove(attribute);
+                }
+            }
+        }
+    }
+
+    // Update provider Services if the properties was changed
+    private void updatePropertyServiceTable() {
+        Object _key;
+        Object _value;
+        Provider.Service s;
+        String serviceName;
+        String algorithm;
+        if (changedProperties == null || changedProperties.isEmpty()) {
+            return;
+        }
+        for (Iterator<Map.Entry<Object, Object>> it = changedProperties.entrySet().iterator(); it
+                .hasNext();) {
+            Map.Entry<Object, Object> entry = it.next();
+            _key = entry.getKey();
+            _value = entry.getValue();
+            if (_key == null || _value == null || !(_key instanceof String)
+                    || !(_value instanceof String)) {
+                continue;
+            }
+            String key = (String) _key;
+            String value = (String) _value;
+            if (key.startsWith("Provider")) { // Provider service type is reserved //$NON-NLS-1$
+                continue;
+            }
+            int i;
+            if (key.startsWith("Alg.Alias.")) { // Alg.Alias.<crypto_service>.<aliasName>=<stanbdardName> //$NON-NLS-1$
+                String aliasName;
+                String service_alias = key.substring(10);
+                i = service_alias.indexOf("."); //$NON-NLS-1$
+                serviceName = service_alias.substring(0, i);
+                aliasName = service_alias.substring(i + 1);
+                algorithm = value;
+                String algUp = algorithm.toUpperCase();
+                Object o = null;
+                if (propertyServiceTable == null) {
+                    propertyServiceTable = new TwoKeyHashMap<String, String, Service>(128);
+                } else {
+                    o = propertyServiceTable.get(serviceName, algUp);
+                }
+                if (o != null) {
+                    s = (Provider.Service) o;
+                    // BEGIN android-changed
+                    s.addAlias(aliasName);
+                    // END android-changed
+                    if (propertyAliasTable == null) {
+                        propertyAliasTable = new TwoKeyHashMap<String, String, Service>(256);
+                    }
+                    propertyAliasTable.put(serviceName,
+                            aliasName.toUpperCase(), s);
+                } else {
+                    String className = (String) changedProperties
+                            .get(serviceName + "." + algorithm); //$NON-NLS-1$
+                    if (className != null) {
+                        List<String> l = new ArrayList<String>();
+                        l.add(aliasName);
+                        s = new Provider.Service(this, serviceName, algorithm,
+                                className, l, new HashMap<String, String>());
+                        propertyServiceTable.put(serviceName, algUp, s);
+                        if (propertyAliasTable == null) {
+                            propertyAliasTable = new TwoKeyHashMap<String, String, Service>(256);
+                        }
+                        propertyAliasTable.put(serviceName, aliasName
+                                .toUpperCase(), s);
+                    }
+                }
+                continue;
+            }
+            int j = key.indexOf("."); //$NON-NLS-1$
+            if (j == -1) { // unknown format
+                continue;
+            }
+            i = key.indexOf(" "); //$NON-NLS-1$
+            if (i == -1) { // <crypto_service>.<algorithm_or_type>=<className>
+                serviceName = key.substring(0, j);
+                algorithm = key.substring(j + 1);
+                String alg = algorithm.toUpperCase();
+                Object o = null;
+                if (propertyServiceTable != null) {
+                    o = propertyServiceTable.get(serviceName, alg);
+                }
+                if (o != null) {
+                    s = (Provider.Service) o;
+                    s.className = value;
+                } else {
+                    // BEGIN android-changed
+                    s = new Provider.Service(this, serviceName, algorithm,
+                            value, Collections.<String>emptyList(),
+                            Collections.<String,String>emptyMap());
+                    // END android-changed
+                    if (propertyServiceTable == null) {
+                        propertyServiceTable = new TwoKeyHashMap<String, String, Service>(128);
+                    }
+                    propertyServiceTable.put(serviceName, alg, s);
+
+                }
+            } else { // <crypto_service>.<algorithm_or_type>
+                     // <attribute_name>=<attrValue>
+                serviceName = key.substring(0, j);
+                algorithm = key.substring(j + 1, i);
+                String attribute = key.substring(i + 1);
+                String alg = algorithm.toUpperCase();
+                Object o = null;
+                if (propertyServiceTable != null) {
+                    o = propertyServiceTable.get(serviceName, alg);
+                }
+                if (o != null) {
+                    s = (Provider.Service) o;
+                    // BEGIN android-changed
+                    s.putAttribute(attribute, value);
+                    // END android-changed
+                } else {
+                    String className = (String) changedProperties
+                            .get(serviceName + "." + algorithm); //$NON-NLS-1$
+                    if (className != null) {
+                        Map<String, String> m = new HashMap<String, String>();
+                        m.put(attribute, value);
+                        s = new Provider.Service(this, serviceName, algorithm,
+                                className, new ArrayList<String>(), m);
+                        if (propertyServiceTable == null) {
+                            propertyServiceTable = new TwoKeyHashMap<String, String, Service>(128);
+                        }
+                        propertyServiceTable.put(serviceName, alg, s);
+                    }
+                }
+            }
+        }
+        servicesChanged();
+        // BEGIN android-changed
+        changedProperties = null;
+        // END android-changed
+    }
+
+    private void servicesChanged() {
+        lastServicesByType = null;
+        lastServiceName = null;
+        lastServicesSet = null;
+    }
+
+    // These attributes should be placed in each Provider object: 
+    // Provider.id name, Provider.id version, Provider.id info, 
+    // Provider.id className
+    private void putProviderInfo() {
+        super.put("Provider.id name", null != name ? name : "null"); //$NON-NLS-1$
+        super.put("Provider.id version", versionString); //$NON-NLS-1$
+        super.put("Provider.id info", null != info ? info : "null"); //$NON-NLS-1$
+        super.put("Provider.id className", this.getClass().getName()); //$NON-NLS-1$
+    }
+
+    // Searches for the property with the specified key in the provider
+    // properties. Key is not case-sensitive.
+    // 
+    // @param prop
+    // @return the property value with the specified key value.
+    private String getPropertyIgnoreCase(String key) {
+        String res = getProperty(key);
+        if (res != null) {
+            return res;
+        }
+        for (Enumeration<?> e = propertyNames(); e.hasMoreElements();) {
+            String pname = (String) e.nextElement();
+            if (key.equalsIgnoreCase(pname)) {
+                return getProperty(pname);
+            }
+        }
+        return null;
+    }
+
+    public static class Service {
+        // The provider
+        private Provider provider;
+
+        // The type of this service
+        private String type;
+
+        // The algorithm name
+        private String algorithm;
+
+        // The class implementing this service
+        private String className;
+
+        // The aliases
+        private List<String> aliases;
+
+        // The attributes
+        private Map<String,String> attributes;
+
+        // Service implementation
+        private Class<?> implementation;
+
+        // For newInstance() optimization
+        private String lastClassName;
+
+        public Service(Provider provider, String type, String algorithm,
+                String className, List<String> aliases, Map<String, String> attributes) {
+            if (provider == null || type == null || algorithm == null
+                    || className == null) {
+                throw new NullPointerException();
+            }
+            this.provider = provider;
+            this.type = type;
+            this.algorithm = algorithm;
+            this.className = className;
+            // BEGIN android-changed
+            this.aliases = ((aliases != null) && (aliases.size() == 0))
+                ? Collections.<String>emptyList() : aliases;
+            this.attributes =
+                ((attributes != null) && (attributes.size() == 0))
+                ? Collections.<String,String>emptyMap() : attributes;
+            // END android-changed
+        }
+
+        // BEGIN android-added
+        /**
+         * Adds an alias.
+         * 
+         * @param alias the alias to add
+         */
+        /*package*/ void addAlias(String alias) {
+            if ((aliases == null) || (aliases.size() == 0)) {
+                aliases = new ArrayList<String>();
+            }
+            aliases.add(alias);
+        }
+
+        /**
+         * Puts a new attribute mapping.
+         * 
+         * @param name the attribute name
+         * @param value the attribute value
+         */
+        /*package*/ void putAttribute(String name, String value) {
+            if ((attributes == null) || (attributes.size() == 0)) {
+                attributes = new HashMap<String,String>();
+            }
+            attributes.put(name, value);
+        }
+        // END android-added
+
+        public final String getType() {
+            return type;
+        }
+
+        public final String getAlgorithm() {
+            return algorithm;
+        }
+
+        public final Provider getProvider() {
+            return provider;
+        }
+
+        public final String getClassName() {
+            return className;
+        }
+
+        public final String getAttribute(String name) {
+            if (name == null) {
+                throw new NullPointerException();
+            }
+            if (attributes == null) {
+                return null;
+            }
+            return attributes.get(name);
+        }
+
+        Iterator<String> getAliases() {
+            return aliases.iterator();
+        }
+
+        public Object newInstance(Object constructorParameter)
+                throws NoSuchAlgorithmException {
+            if (implementation == null || !className.equals(lastClassName)) {
+                NoSuchAlgorithmException result = AccessController
+                        .doPrivileged(new PrivilegedAction<NoSuchAlgorithmException>() {
+                            public NoSuchAlgorithmException run() {
+                                ClassLoader cl = provider.getClass()
+                                        .getClassLoader();
+                                if (cl == null) {
+                                    cl = ClassLoader.getSystemClassLoader();
+                                }
+                                try {
+                                    implementation = Class.forName(className,
+                                            true, cl);
+                                } catch (Exception e) {
+                                    return new NoSuchAlgorithmException(
+                                            Messages.getString("security.11",  //$NON-NLS-1$
+                                                    new Object[]{type, algorithm, e}));
+                                }
+                                lastClassName = className;
+                                return null;
+                            }
+                        });
+                if (result != null) {
+                    throw result;
+                }
+            }
+            if (constructorParameter == null) {
+                try {
+                    return implementation.newInstance();
+                } catch (Exception e) {
+                    throw new NoSuchAlgorithmException(Messages.getString("security.199", //$NON-NLS-1$
+                            type, algorithm), e);
+                }
+            } else {
+                if (!supportsParameter(constructorParameter)) {
+                    throw new InvalidParameterException(
+                            Messages.getString("security.12", type)); //$NON-NLS-1$
+                }
+
+                Class[] parameterTypes = new Class[1];
+                Object[] initargs = { constructorParameter };
+                try {
+                    if (type.equalsIgnoreCase("CertStore")) { //$NON-NLS-1$
+                        parameterTypes[0] = Class
+                                .forName("java.security.cert.CertStoreParameters"); //$NON-NLS-1$
+                    } else {
+                        parameterTypes[0] = constructorParameter.getClass();
+                    }
+                    return implementation.getConstructor(parameterTypes)
+                            .newInstance(initargs);
+                } catch (Exception e) {
+                    throw new NoSuchAlgorithmException(Messages.getString("security.199", //$NON-NLS-1$
+                            type, algorithm), e);
+                }
+            }
+        }
+
+        public boolean supportsParameter(Object parameter) {
+            return true;
+        }
+
+    /**
+     * Returns a string containing a concise, human-readable
+     * description of the receiver.
+     * 
+     * 
+     * @return a printable representation for the receiver.
+     */
+        public String toString() {
+            String result = "Provider " + provider.getName() + " Service " //$NON-NLS-1$ //$NON-NLS-2$
+                    + type + "." + algorithm + " " + className; //$NON-NLS-1$ //$NON-NLS-2$
+            if (aliases != null) {
+                result = result + "\nAliases " + aliases.toString(); //$NON-NLS-1$
+            }
+            if (attributes != null) {
+                result = result + "\nAttributes " + attributes.toString(); //$NON-NLS-1$
+            }
+            return result;
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/ProviderException.java b/libcore/security/src/main/java/java/security/ProviderException.java
new file mode 100644
index 0000000..6ca33ab
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/ProviderException.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class ProviderException extends RuntimeException {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = 5256023526693665674L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public ProviderException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public ProviderException() {
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public ProviderException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public ProviderException(Throwable cause) {
+        super(cause);
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/PublicKey.java b/libcore/security/src/main/java/java/security/PublicKey.java
new file mode 100644
index 0000000..ff68e28
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/PublicKey.java
@@ -0,0 +1,37 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * Superinterface for all specific public key interfaces
+ * 
+ * 
+ * @see PublicKey
+ * @see PrivateKey
+ */
+public interface PublicKey extends Key {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public static final long serialVersionUID = 7187392471159151072L;
+}
diff --git a/libcore/security/src/main/java/java/security/SecureClassLoader.java b/libcore/security/src/main/java/java/security/SecureClassLoader.java
new file mode 100644
index 0000000..ed1a7b0
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/SecureClassLoader.java
@@ -0,0 +1,107 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Astapchuk
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+
+/**
+ * SecureClassLoaders are used to dynamically load, link and install classes
+ * into a running image. Additionally, they (optionally) associate the classes
+ * they create with a code source and provide mechanisms to allow the relevant
+ * permissions to be retrieved.
+ * 
+ */
+
+public class SecureClassLoader extends ClassLoader {
+
+    // A cache of ProtectionDomains for a given CodeSource
+    private HashMap pds = new HashMap();
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    protected SecureClassLoader() {
+        super();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    protected SecureClassLoader(ClassLoader parent) {
+        super(parent);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    protected PermissionCollection getPermissions(CodeSource codesource) {
+        // Do nothing by default, ProtectionDomain will take care about
+        // permissions in dynamic
+        return new Permissions();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    protected final Class<?> defineClass(String name, byte[] b, int off, int len,
+            CodeSource cs) {
+        return cs == null ? defineClass(name, b, off, len) : defineClass(name,
+                b, off, len, getPD(cs));
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    protected final Class<?> defineClass(String name, ByteBuffer b, CodeSource cs) {
+        //FIXME 1.5 - remove b.array(), call super.defineClass(,ByteBuffer,)
+        // directly
+        byte[] data = b.array();
+        return cs == null ? defineClass(name, data, 0, data.length)
+                : defineClass(name, data, 0, data.length, getPD(cs));
+    }
+
+    // Constructs and caches ProtectionDomain for the given CodeSource 
+    // object.<br>
+    // It calls {@link getPermissions()} to get a set of permissions.
+    //
+    // @param cs CodeSource object
+    // @return ProtectionDomain for the passed CodeSource object
+    private ProtectionDomain getPD(CodeSource cs) {
+        if (cs == null) {
+            return null;
+        }
+        // need to cache PDs, otherwise every class from a given CodeSource 
+        // will have it's own ProtectionDomain, which does not look right.
+        ProtectionDomain pd;
+        synchronized (pds) {
+            if ((pd = (ProtectionDomain) pds.get(cs)) != null) {
+                return pd;
+            }
+            PermissionCollection perms = getPermissions(cs);
+            pd = new ProtectionDomain(cs, perms, this, null);
+            pds.put(cs, pd);
+        }
+        return pd;
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/SecureRandom.java b/libcore/security/src/main/java/java/security/SecureRandom.java
new file mode 100644
index 0000000..0cf5353
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/SecureRandom.java
@@ -0,0 +1,335 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris V. Kuznetsov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.util.Iterator;
+import java.util.Random;
+import java.util.Set;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.fortress.Services;
+import org.apache.harmony.security.internal.nls.Messages;
+
+import org.apache.harmony.security.provider.crypto.SHA1PRNG_SecureRandomImpl;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public class SecureRandom extends Random {
+    
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    private static final long serialVersionUID = 4940670005562187L;
+    
+    // The service name.
+    private static final transient String SERVICE = "SecureRandom"; //$NON-NLS-1$
+    
+    // Used to access common engine functionality
+    private static transient Engine engine = new Engine(SERVICE);
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private Provider provider;
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private SecureRandomSpi secureRandomSpi; 
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private String algorithm;
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private byte[] state;
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private byte[] randomBytes;
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private int randomBytesUsed;
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private long counter;
+    
+    // Internal SecureRandom used for getSeed(int)
+    private static transient SecureRandom internalSecureRandom;
+    
+    /**
+     * Constructs a new instance of this class. Users are encouraged to use
+     * <code>getInstance()</code> instead.
+     * 
+     * An implementation for the highest-priority provider is returned. The
+     * instance returned will not have been seeded.
+     */
+    public SecureRandom() {
+        super(0);
+        Provider.Service service = findService();
+        if (service == null) {
+            this.provider = null;
+            this.secureRandomSpi = new SHA1PRNG_SecureRandomImpl();
+            this.algorithm = "SHA1PRNG"; //$NON-NLS-1$
+        } else {
+            try {
+                this.provider = service.getProvider();
+                this.secureRandomSpi = (SecureRandomSpi)service.newInstance(null);
+                this.algorithm = service.getAlgorithm();
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }            
+        }    
+    }
+
+    /**
+     * Constructs a new instance of this class. Users are encouraged to use
+     * <code>getInstance()</code> instead.
+     * 
+     * An implementation for the highest-priority provider is returned. The
+     * instance returned will be seeded with the parameter.
+     * 
+     * @param seed
+     *            bytes forming the seed for this generator.
+     */
+    public SecureRandom(byte[] seed) {
+        this();
+        setSeed(seed);
+    }
+    
+    //Find SecureRandom service.
+    private Provider.Service findService() {
+        Set s;
+        Provider.Service service;
+        for (Iterator it1 = Services.getProvidersList().iterator(); it1.hasNext();) {
+            service = ((Provider)it1.next()).getService("SecureRandom"); //$NON-NLS-1$
+            if (service != null) {
+                return service;
+            }
+        }
+        return null;
+    }
+    
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    protected SecureRandom(SecureRandomSpi secureRandomSpi,
+                           Provider provider) {
+        this(secureRandomSpi, provider, "unknown"); //$NON-NLS-1$
+    }
+    
+    // Constructor
+    private SecureRandom(SecureRandomSpi secureRandomSpi,
+                         Provider provider,
+                         String algorithm) {
+        super(0);
+        this.provider = provider;
+        this.algorithm = algorithm;
+        this.secureRandomSpi = secureRandomSpi;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    public static SecureRandom getInstance(String algorithm)
+                                throws NoSuchAlgorithmException {
+        if (algorithm == null) {
+            throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+        }
+        synchronized (engine) {
+            engine.getInstance(algorithm, null);
+            return new SecureRandom((SecureRandomSpi)engine.spi, engine.provider, algorithm);
+        }
+    }
+
+    /**
+     * Returns a new SecureRandom which is capable of running the algorithm
+     * described by the argument. The result will be an instance of a subclass
+     * of SecureRandomSpi which implements that algorithm.
+     * 
+     * @param algorithm
+     *            java.lang.String Name of the algorithm desired
+     * @param provider
+     *            java.security.Provider Provider which has to implement the
+     *            algorithm
+     * @return SecureRandom a concrete implementation for the algorithm desired.
+     * 
+     * @exception NoSuchAlgorithmException
+     *                If the algorithm cannot be found
+     */
+    public static SecureRandom getInstance(String algorithm, String provider)
+                                throws NoSuchAlgorithmException, NoSuchProviderException {
+        if ((provider == null) || (provider.length() == 0)) {
+            throw new IllegalArgumentException(
+                    Messages.getString("security.02")); //$NON-NLS-1$
+        }
+        Provider p = Security.getProvider(provider);
+        if (p == null) {
+            throw new NoSuchProviderException(Messages.getString("security.03", provider));  //$NON-NLS-1$
+        }
+        return getInstance(algorithm, p);    
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    public static SecureRandom getInstance(String algorithm, Provider provider)
+                                throws NoSuchAlgorithmException {
+        if (provider == null) {
+            throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
+        }
+        if (algorithm == null) {
+            throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+        }
+        synchronized (engine) {
+            engine.getInstance(algorithm, provider, null);
+            return new SecureRandom((SecureRandomSpi)engine.spi, provider, algorithm);
+        }
+    }
+
+    /**
+     * Returns the Provider of the secure random represented by the receiver.
+     * 
+     * @return Provider an instance of a subclass of java.security.Provider
+     */
+    public final Provider getProvider() {
+        return provider;
+    }
+    
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    public String getAlgorithm() {
+        return algorithm;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    public synchronized void setSeed(byte[] seed) {
+        secureRandomSpi.engineSetSeed(seed);
+    }
+
+    /**
+     * Reseeds this random object with the eight bytes described by the
+     * representation of the long provided.
+     * 
+     * 
+     * @param seed
+     *            long Number whose representation to use to reseed the
+     *            receiver.
+     */
+    public void setSeed(long seed) {
+        if (seed == 0) {    // skip call from Random
+            return;
+        }
+        byte[] byteSeed = {
+                (byte)((seed >> 56) & 0xFF),
+                (byte)((seed >> 48) & 0xFF),
+                (byte)((seed >> 40) & 0xFF),
+                (byte)((seed >> 32) & 0xFF),
+                (byte)((seed >> 24) & 0xFF),
+                (byte)((seed >> 16) & 0xFF),
+                (byte)((seed >> 8) & 0xFF),
+                (byte)((seed) & 0xFF)
+        };
+        setSeed(byteSeed);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    public synchronized void nextBytes(byte[] bytes) {
+        secureRandomSpi.engineNextBytes(bytes);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    protected final int next(int numBits) {
+        if (numBits < 0) {
+            numBits = 0;
+        } else {
+            if (numBits > 32) {
+                numBits = 32;
+            }
+        }
+        int bytes = (numBits+7)/8;
+        byte[] next = new byte[bytes];
+        int ret = 0;
+         
+        nextBytes(next);
+        for (int i = 0; i < bytes; i++) {
+            ret = (next[i] & 0xFF) | (ret << 8);
+        }    
+        ret = ret >>> (bytes*8 - numBits);
+        return ret;
+    }
+
+    /**
+     * Returns the given number of seed bytes, computed using the seed
+     * generation algorithm used by this class.
+     * 
+     * @param numBytes
+     *            int the given number of seed bytes
+     * @return byte[] The seed bytes generated
+     */
+    public static byte[] getSeed(int numBytes) {
+        if (internalSecureRandom == null) {
+            internalSecureRandom = new SecureRandom();
+        }
+        return internalSecureRandom.generateSeed(numBytes);
+    }
+
+    /**
+     * Generates a certain number of seed bytes
+     * 
+     * 
+     * @param numBytes
+     *            int Number of seed bytes to generate
+     * @return byte[] The seed bytes generated
+     */
+    public byte[] generateSeed(int numBytes) {
+        return secureRandomSpi.engineGenerateSeed(numBytes);
+    }
+    
+}
diff --git a/libcore/security/src/main/java/java/security/SecureRandomSpi.java b/libcore/security/src/main/java/java/security/SecureRandomSpi.java
new file mode 100644
index 0000000..1eb9c1a
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/SecureRandomSpi.java
@@ -0,0 +1,57 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris V. Kuznetsov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.Serializable;
+
+/**
+ * This class is a Service Provider Interface (therefore the Spi suffix) for
+ * secure random number generation algorithms to be supplied by providers.
+ * 
+ */
+public abstract class SecureRandomSpi implements Serializable {
+    
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    private static final long serialVersionUID = -2991854161009191830L;
+                
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    protected abstract void engineSetSeed(byte[] seed);
+    
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    protected abstract void engineNextBytes(byte[] bytes);
+    
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    protected abstract byte[] engineGenerateSeed(int numBytes);
+}
diff --git a/libcore/security/src/main/java/java/security/Security.java b/libcore/security/src/main/java/java/security/Security.java
new file mode 100644
index 0000000..28fd210
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/Security.java
@@ -0,0 +1,457 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris V. Kuznetsov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.Enumeration;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.fortress.PolicyUtils;
+import org.apache.harmony.security.fortress.SecurityAccess;
+import org.apache.harmony.security.fortress.Services;
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * For access to security providers and properties.
+ */
+public final class Security {
+
+    // Security properties
+    private static Properties secprops = new Properties();
+
+    // static initialization
+    // - load security properties files
+    // - load statically registered providers
+    // - if no provider description file found then load default providers
+    static {
+        AccessController.doPrivileged(new java.security.PrivilegedAction<Void>() {
+            public Void run() {
+                boolean loaded = false;
+                
+                // BEGIN android-added
+                /*
+                 * Android only uses a local "security.properties" resource
+                 * for configuration. TODO: Reevaluate this decision.
+                 */
+                try {
+                    InputStream configStream =
+                        getClass().getResourceAsStream("security.properties"); //$NON-NLS-1$
+                    InputStream input =
+                        new BufferedInputStream(configStream, 8192);
+                    secprops.load(input);
+                    loaded = true;
+                    configStream.close();
+                } catch (Exception ex) {
+                    Logger.global.log(Level.SEVERE,
+                            "Could not load Security properties.", ex);
+                }
+                // END android-added
+
+                // BEGIN android-removed
+//                File f = new File(System.getProperty("java.home") //$NON-NLS-1$
+//                        + File.separator + "lib" + File.separator //$NON-NLS-1$
+//                        + "security" + File.separator + "java.security"); //$NON-NLS-1$ //$NON-NLS-2$
+//                if (f.exists()) {
+//                    try {
+//                        FileInputStream fis = new FileInputStream(f);
+//                        InputStream is = new BufferedInputStream(fis);
+//                        secprops.load(is);
+//                        loaded = true;
+//                        is.close();
+//                    } catch (IOException e) {
+////                        System.err.println("Could not load Security properties file: "
+////                                        + e);
+//                    }
+//                }
+//
+//                if ("true".equalsIgnoreCase(secprops.getProperty("security.allowCustomPropertiesFile", "true"))) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+//                    String securityFile = System.getProperty("java.security.properties"); //$NON-NLS-1$
+//                    if (securityFile != null) {
+//                        if (securityFile.startsWith("=")) { // overwrite //$NON-NLS-1$
+//                            secprops = new Properties();
+//                            loaded = false;
+//                            securityFile = securityFile.substring(1);
+//                        }
+//                        try {
+//                            securityFile = PolicyUtils.expand(securityFile, System.getProperties());
+//                        } catch (PolicyUtils.ExpansionFailedException e) {
+////                            System.err.println("Could not load custom Security properties file "
+////                                    + securityFile +": " + e);
+//                        }
+//                        f = new File(securityFile);
+//                        InputStream is;
+//                        try {
+//                            if (f.exists()) {
+//                                FileInputStream fis = new FileInputStream(f);
+//                                is = new BufferedInputStream(fis);
+//                            } else {
+//                                URL url = new URL(securityFile);
+//                                is = new BufferedInputStream(url.openStream());
+//                            }
+//                            secprops.load(is);
+//                            loaded = true;
+//                            is.close();
+//                        } catch (IOException e) {
+// //                           System.err.println("Could not load custom Security properties file "
+// //                                   + securityFile +": " + e);
+//                        }
+//                    }
+//                }
+                // END android-removed
+
+                if (!loaded) {
+                    registerDefaultProviders();
+                }
+                Engine.door = new SecurityDoor();
+                return null;
+            }
+        });
+    }
+
+    /**
+     * This class can't be instantiated.
+     */
+    private Security() {
+    }
+
+    // Register default providers
+    private static void registerDefaultProviders() {
+        secprops.put("security.provider.1", "org.apache.harmony.security.provider.cert.DRLCertFactory");  //$NON-NLS-1$ //$NON-NLS-2$
+        secprops.put("security.provider.2", "org.apache.harmony.security.provider.crypto.CryptoProvider");  //$NON-NLS-1$ //$NON-NLS-2$
+        secprops.put("security.provider.3", "org.apache.harmony.xnet.provider.jsse.JSSEProvider");  //$NON-NLS-1$ //$NON-NLS-2$
+        secprops.put("security.provider.4", "org.bouncycastle.jce.provider.BouncyCastleProvider");  //$NON-NLS-1$ //$NON-NLS-2$
+    }
+
+    /**
+     * Deprecated method which returns null.
+     * @param algName 
+     * @param propName 
+     * @return <code>null</code>
+     *
+     * @deprecated    Use AlgorithmParameters and KeyFactory instead
+     */
+    public static String getAlgorithmProperty(String algName, String propName) {
+        if (algName == null || propName == null) {
+            return null;
+        }
+        String prop = propName + "." + algName; //$NON-NLS-1$
+        Provider[] providers = getProviders();
+        for (int i = 0; i < providers.length; i++) {
+            for (Enumeration e = providers[i].propertyNames(); e
+                    .hasMoreElements();) {
+                String pname = (String) e.nextElement();
+                if (prop.equalsIgnoreCase(pname)) {
+                    return providers[i].getProperty(pname);
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public static synchronized int insertProviderAt(Provider provider,
+            int position) {
+        // check security access; check that provider is not already
+        // installed, else return -1; if (position <1) or (position > max
+        // position) position = max position + 1; insert provider, shift up
+        // one position for next providers; Note: The position is 1-based
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("insertProvider." + provider.getName()); //$NON-NLS-1$
+        }
+        if (getProvider(provider.getName()) != null) {
+            return -1;
+        }
+        int result = Services.insertProviderAt(provider, position);
+        renumProviders();
+        return result;
+    }
+
+    /**
+     * Adds the extra provider to the collection of providers.
+     * @param provider 
+     * 
+     * @return int The priority/position of the provider added.
+     * @exception SecurityException
+     *                If there is a SecurityManager installed and it denies
+     *                adding a new provider.
+     */
+    public static int addProvider(Provider provider) {
+        return insertProviderAt(provider, 0);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public static synchronized void removeProvider(String name) {
+        // It is not clear from spec.:
+        // 1. if name is null, should we checkSecurityAccess or not? 
+        //    throw SecurityException or not?
+        // 2. as 1 but provider is not installed
+        // 3. behavior if name is empty string?
+
+        Provider p;
+        if ((name == null) || (name.length() == 0)) {
+            return;
+        }
+        p = getProvider(name);
+        if (p == null) {
+            return;
+        }
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("removeProvider." + name); //$NON-NLS-1$
+        }
+        Services.removeProvider(p.getProviderNumber());
+        renumProviders();
+        p.setProviderNumber(-1);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public static synchronized Provider[] getProviders() {
+        return Services.getProviders();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public static synchronized Provider getProvider(String name) {
+        return Services.getProvider(name);
+    }
+
+    /**
+     * Returns the collection of providers which meet the user supplied string
+     * filter.
+     * 
+     * @param filter
+     *            case-insensitive filter
+     * @return the providers which meet the user supplied string filter
+     *         <code>filter</code>. A <code>null</code> value signifies
+     *         that none of the installed providers meets the filter
+     *         specification
+     * @exception InvalidParameterException
+     *                if an unusable filter is supplied
+     */
+    public static Provider[] getProviders(String filter) {
+        if (filter == null) {
+            throw new NullPointerException(Messages.getString("security.2A")); //$NON-NLS-1$
+        }
+        if (filter.length() == 0) {
+            throw new InvalidParameterException(
+                    Messages.getString("security.2B")); //$NON-NLS-1$
+        }
+        HashMap<String, String> hm = new HashMap<String, String>();
+        int i = filter.indexOf(":"); //$NON-NLS-1$
+        if ((i == filter.length() - 1) || (i == 0)) {
+            throw new InvalidParameterException(
+                    Messages.getString("security.2B")); //$NON-NLS-1$
+        }
+        if (i < 1) {
+            hm.put(filter, ""); //$NON-NLS-1$
+        } else {
+            hm.put(filter.substring(0, i), filter.substring(i + 1));
+        }
+        return getProviders(hm);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public static synchronized Provider[] getProviders(Map<String,String> filter) {
+        if (filter == null) {
+            throw new NullPointerException(Messages.getString("security.2A")); //$NON-NLS-1$
+        }
+        if (filter.isEmpty()) {
+            return null;
+        }
+        java.util.List<Provider> result = Services.getProvidersList();
+        Set keys = filter.entrySet();
+        Map.Entry entry;
+        for (Iterator it = keys.iterator(); it.hasNext();) {
+            entry = (Map.Entry) it.next();
+            String key = (String) entry.getKey();
+            String val = (String) entry.getValue();
+            String attribute = null;
+            int i = key.indexOf(" "); //$NON-NLS-1$
+            int j = key.indexOf("."); //$NON-NLS-1$
+            if (j == -1) {
+                throw new InvalidParameterException(
+                        Messages.getString("security.2B")); //$NON-NLS-1$
+            }
+            if (i == -1) { // <crypto_service>.<algorithm_or_type>
+                if (val.length() != 0) {
+                    throw new InvalidParameterException(
+                            Messages.getString("security.2B")); //$NON-NLS-1$
+                }
+            } else { // <crypto_service>.<algorithm_or_type> <attribute_name>
+                if (val.length() == 0) {
+                    throw new InvalidParameterException(
+                            Messages.getString("security.2B")); //$NON-NLS-1$
+                }
+                attribute = key.substring(i + 1);
+                if (attribute.trim().length() == 0) {
+                    throw new InvalidParameterException(
+                            Messages.getString("security.2B")); //$NON-NLS-1$
+                }
+                key = key.substring(0, i);
+            }
+            String serv = key.substring(0, j);
+            String alg = key.substring(j + 1);
+            if (serv.length() == 0 || alg.length() == 0) {
+                throw new InvalidParameterException(
+                        Messages.getString("security.2B")); //$NON-NLS-1$
+            }
+            Provider p;
+            for (int k = 0; k < result.size(); k++) {
+                try {
+                    p = (Provider) result.get(k);
+                } catch (IndexOutOfBoundsException e) {
+                    break;
+                }
+                if (!p.implementsAlg(serv, alg, attribute, val)) {
+                    result.remove(p);
+                    k--;
+                }
+            }
+        }
+        if (result.size() > 0) {
+            return result.toArray(new Provider[result.size()]);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Returns the value of the security property named by the argument.
+     * 
+     * 
+     * @param key
+     *            String The property name
+     * @return String The property value
+     * 
+     * @exception SecurityException
+     *                If there is a SecurityManager installed and it will not
+     *                allow the property to be fetched from the current access
+     *                control context.
+     */
+    public static String getProperty(String key) {
+        if (key == null) {
+            throw new NullPointerException(Messages.getString("security.2C")); //$NON-NLS-1$
+        }
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("getProperty." + key); //$NON-NLS-1$
+        }
+        return secprops.getProperty(key);
+    }
+
+    /**
+     * Sets a given security property.
+     * 
+     * 
+     * @param key
+     *            String The property name.
+     * @param datnum
+     *            String The property value.
+     * @exception SecurityException
+     *                If there is a SecurityManager installed and it will not
+     *                allow the property to be set from the current access
+     *                control context.
+     */
+    public static void setProperty(String key, String datnum) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("setProperty." + key); //$NON-NLS-1$
+        }
+        secprops.put(key, datnum);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public static Set<String> getAlgorithms(String serviceName) {
+        Set<String> result = new HashSet<String>();
+        Provider[] p = getProviders();
+        for (int i = 0; i < p.length; i++) {
+            for (Iterator it = p[i].getServices().iterator(); it.hasNext();) {
+                Provider.Service s = (Provider.Service) it.next();
+                if (s.getType().equalsIgnoreCase(serviceName)) {
+                    result.add(s.getAlgorithm());
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * 
+     * Update sequence numbers of all providers
+     *  
+     */
+    private static void renumProviders() {
+        Provider[] p = Services.getProviders();
+        for (int i = 0; i < p.length; i++) {
+            p[i].setProviderNumber(i + 1);
+        }
+    }
+
+    private static class SecurityDoor implements SecurityAccess {
+        // Access to Security.renumProviders()
+        public void renumProviders() {
+            Security.renumProviders();
+        }
+
+        //  Access to Security.getAliases()
+        public Iterator<String> getAliases(Provider.Service s) {
+            return s.getAliases();
+        }
+        
+        // Access to Provider.getService()
+        public Provider.Service getService(Provider p, String type) {
+            return p.getService(type);
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/SecurityPermission.java b/libcore/security/src/main/java/java/security/SecurityPermission.java
new file mode 100644
index 0000000..f331b18
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/SecurityPermission.java
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * SecurityPermission objects guard access to the mechanisms which implement
+ * security. Security permissions have names, but not actions.
+ * 
+ */
+public final class SecurityPermission extends BasicPermission {
+
+    /** 
+     * @com.intel.drl.spec_ref 
+     */
+    private static final long serialVersionUID = 5236109936224050470L;
+
+    /**
+     * Creates an instance of this class with the given name.
+     * 
+     * @param name
+     *            String the name of the new permission.
+     */
+    public SecurityPermission(String name) {
+        super(name);
+    }
+
+    /**
+     * Creates an instance of this class with the given name and action list.
+     * The action list is ignored.
+     * 
+     * @param name
+     *            String the name of the new permission.
+     * @param action
+     *            String ignored.
+     */
+    public SecurityPermission(String name, String action) {
+        super(name, action);
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/Signature.java b/libcore/security/src/main/java/java/security/Signature.java
new file mode 100644
index 0000000..0711d8f
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/Signature.java
@@ -0,0 +1,503 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris V. Kuznetsov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.nio.ByteBuffer;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public abstract class Signature extends SignatureSpi {
+    
+    // The service name.
+    private static final String SERVICE = "Signature"; //$NON-NLS-1$
+
+    // Used to access common engine functionality
+    private static Engine engine = new Engine(SERVICE);
+
+    // The provider
+    private Provider provider;
+
+    // The algorithm.
+    private String algorithm;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected static final int UNINITIALIZED = 0;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected static final int SIGN = 2;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected static final int VERIFY = 3;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected int state = UNINITIALIZED;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected Signature(String algorithm) {
+        this.algorithm = algorithm;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public static Signature getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        if (algorithm == null) {
+            throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+        }
+        Signature result;
+        synchronized (engine) {
+            engine.getInstance(algorithm, null);
+            if (engine.spi instanceof Signature) {
+                result = (Signature) engine.spi;
+                result.algorithm = algorithm;
+                result.provider = engine.provider;
+            } else {
+                result = new SignatureImpl((SignatureSpi) engine.spi,
+                        engine.provider, algorithm);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public static Signature getInstance(String algorithm, String provider)
+            throws NoSuchAlgorithmException, NoSuchProviderException {
+        if (algorithm == null) {
+            throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+        }
+        if ((provider == null) || (provider.length() == 0)) {
+            throw new IllegalArgumentException(
+                    Messages.getString("security.02")); //$NON-NLS-1$
+        }
+        Provider p = Security.getProvider(provider);
+        if (p == null) {
+            throw new NoSuchProviderException(Messages.getString("security.03", provider)); //$NON-NLS-1$
+        }
+        return getSignatureInstance(algorithm, p);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public static Signature getInstance(String algorithm, Provider provider)
+            throws NoSuchAlgorithmException {
+        if (algorithm == null) {
+            throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+        }
+        if (provider == null) {
+            throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
+        }
+        return getSignatureInstance(algorithm, provider);
+    }
+    
+    private static Signature getSignatureInstance(String algorithm,
+            Provider provider) throws NoSuchAlgorithmException {
+        Signature result;
+        synchronized (engine) {
+            engine.getInstance(algorithm, provider, null);
+            if (engine.spi instanceof Signature) {
+                result = (Signature) engine.spi;
+                result.algorithm = algorithm;
+                result.provider = provider;
+            } else {
+                result = new SignatureImpl((SignatureSpi) engine.spi, provider,
+                        algorithm);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final Provider getProvider() {
+        return provider;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final String getAlgorithm() {
+        return algorithm;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final void initVerify(PublicKey publicKey)
+            throws InvalidKeyException {
+        engineInitVerify(publicKey);
+        state = VERIFY;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final void initVerify(Certificate certificate)
+            throws InvalidKeyException {
+        if (certificate instanceof X509Certificate) {
+            Set ce = ((X509Certificate) certificate).getCriticalExtensionOIDs();
+            boolean critical = false;
+            if (ce != null && !ce.isEmpty()) {
+                for (Iterator i = ce.iterator(); i.hasNext();) {
+                    if ("2.5.29.15".equals(i.next())) {  //$NON-NLS-1$
+                        //KeyUsage OID = 2.5.29.15
+                        critical = true;
+                        break;
+                    }
+                }
+                if (critical) {
+                    boolean[] keyUsage = ((X509Certificate) certificate)
+                            .getKeyUsage();
+                    // As specified in RFC 3280 -
+                    // Internet X.509 Public Key Infrastructure
+                    // Certificate and Certificate Revocation List (CRL) Profile.
+                    // (http://www.ietf.org/rfc/rfc3280.txt)
+                    //
+                    // KeyUsage ::= BIT STRING { digitalSignature (0), <skipped> }
+                    if ((keyUsage != null) && (!keyUsage[0])) { // digitalSignature
+                        throw new InvalidKeyException(
+                                Messages.getString("security.26")); //$NON-NLS-1$
+                    }
+                }
+            }
+        }
+        engineInitVerify(certificate.getPublicKey());
+        state = VERIFY;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final void initSign(PrivateKey privateKey)
+            throws InvalidKeyException {
+        engineInitSign(privateKey);
+        state = SIGN;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final void initSign(PrivateKey privateKey, SecureRandom random)
+            throws InvalidKeyException {
+        engineInitSign(privateKey, random);
+        state = SIGN;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final byte[] sign() throws SignatureException {
+        if (state != SIGN) {
+            throw new SignatureException(
+                    Messages.getString("security.27")); //$NON-NLS-1$
+        }
+        return engineSign();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final int sign(byte[] outbuf, int offset, int len)
+            throws SignatureException {       
+        if (outbuf == null || offset < 0 || len < 0 ||
+                offset + len > outbuf.length) {
+            throw new IllegalArgumentException(
+                    Messages.getString("security.05")); //$NON-NLS-1$
+        }
+        if (state != SIGN) {
+            throw new SignatureException(
+                    Messages.getString("security.27")); //$NON-NLS-1$
+        }
+        return engineSign(outbuf, offset, len);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final boolean verify(byte[] signature) throws SignatureException {
+        if (state != VERIFY) {
+            throw new SignatureException(
+                    Messages.getString("security.27")); //$NON-NLS-1$
+        }
+        return engineVerify(signature);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final boolean verify(byte[] signature, int offset, int length)
+            throws SignatureException {
+        if (state != VERIFY) {
+            throw new SignatureException(
+                    Messages.getString("security.27")); //$NON-NLS-1$
+        }
+        if (signature == null || offset < 0 || length < 0 ||
+                offset + length > signature.length) {
+            throw new IllegalArgumentException(
+                    Messages.getString("security.05")); //$NON-NLS-1$
+        }
+        return engineVerify(signature, offset, length);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final void update(byte b) throws SignatureException {
+        if (state == UNINITIALIZED) {
+            throw new SignatureException(
+                    Messages.getString("security.27")); //$NON-NLS-1$
+        }
+        engineUpdate(b);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final void update(byte[] data) throws SignatureException {
+        if (state == UNINITIALIZED) {
+            throw new SignatureException(
+                    Messages.getString("security.27")); //$NON-NLS-1$
+        }
+        engineUpdate(data, 0, data.length);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final void update(byte[] data, int off, int len)
+            throws SignatureException {
+        if (state == UNINITIALIZED) {
+            throw new SignatureException(
+                    Messages.getString("security.27")); //$NON-NLS-1$
+        }
+        if (data == null || off < 0 || len < 0 ||
+                off + len > data.length) {
+            throw new IllegalArgumentException(
+                    Messages.getString("security.05")); //$NON-NLS-1$
+        }
+        engineUpdate(data, off, len);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final void update(ByteBuffer data) throws SignatureException {
+        if (state == UNINITIALIZED) {
+            throw new SignatureException(
+                    Messages.getString("security.27")); //$NON-NLS-1$
+        }
+        engineUpdate(data);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public String toString() {
+        return "SIGNATURE " + algorithm + " state: " + stateToString(state); //$NON-NLS-1$ //$NON-NLS-2$
+    }
+
+    // Convert state to string
+    private String stateToString(int state) {
+        switch (state) {
+        case UNINITIALIZED:
+            return "UNINITIALIZED"; //$NON-NLS-1$
+        case SIGN:
+            return "SIGN"; //$NON-NLS-1$
+        case VERIFY:
+            return "VERIFY"; //$NON-NLS-1$
+        default:
+            return ""; //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     * @deprecated Use {@link Signature#setParameter(AlgorithmParameterSpec) setParameter}
+     */
+    public final void setParameter(String param, Object value)
+            throws InvalidParameterException {
+        engineSetParameter(param, value);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final void setParameter(AlgorithmParameterSpec params)
+            throws InvalidAlgorithmParameterException {
+        engineSetParameter(params);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public final AlgorithmParameters getParameters() {
+        return engineGetParameters();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     * @deprecated There is no generally accepted parameter naming convention.
+     */
+    public final Object getParameter(String param)
+            throws InvalidParameterException {
+        return engineGetParameter(param);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public Object clone() throws CloneNotSupportedException {
+        if (this instanceof Cloneable) {
+            return super.clone();
+        } else {
+            throw new CloneNotSupportedException();
+        }
+    }
+
+    /**
+     * 
+     * Internal Signature implementation
+     * 
+     */
+    private static class SignatureImpl extends Signature {
+
+        private SignatureSpi spiImpl;
+
+        // Constructor
+        public SignatureImpl(SignatureSpi signatureSpi, Provider provider,
+                String algorithm) {
+            super(algorithm);
+            super.provider = provider;
+            spiImpl = signatureSpi;
+        }
+
+        // engineSign() implementation
+        protected byte[] engineSign() throws SignatureException {
+            return spiImpl.engineSign();
+        }
+
+        //  engineUpdate() implementation
+        protected void engineUpdate(byte arg0) throws SignatureException {
+            spiImpl.engineUpdate(arg0);
+        }
+
+        // engineVerify() implementation
+        protected boolean engineVerify(byte[] arg0) throws SignatureException {
+            return spiImpl.engineVerify(arg0);
+        }
+
+        // engineUpdate() implementation
+        protected void engineUpdate(byte[] arg0, int arg1, int arg2)
+                throws SignatureException {
+            spiImpl.engineUpdate(arg0, arg1, arg2);
+        }
+
+        // engineInitSign() implementation
+        protected void engineInitSign(PrivateKey arg0)
+                throws InvalidKeyException {
+            spiImpl.engineInitSign(arg0);
+        }
+
+        // engineInitVerify() implementation
+        protected void engineInitVerify(PublicKey arg0)
+                throws InvalidKeyException {
+            spiImpl.engineInitVerify(arg0);
+        }
+
+        // engineGetParameter() implementation
+        protected Object engineGetParameter(String arg0)
+                throws InvalidParameterException {
+            return spiImpl.engineGetParameter(arg0);
+        }
+
+        // engineSetParameter() implementation
+        protected void engineSetParameter(String arg0, Object arg1)
+                throws InvalidParameterException {
+            spiImpl.engineSetParameter(arg0, arg1);
+        }
+
+        // Returns a clone if the spiImpl is cloneable
+        public Object clone() throws CloneNotSupportedException {
+            if (spiImpl instanceof Cloneable) {
+                SignatureSpi spi = (SignatureSpi) spiImpl.clone();
+                return new SignatureImpl(spi, getProvider(), getAlgorithm());
+            } else {
+                throw new CloneNotSupportedException();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/SignatureException.java b/libcore/security/src/main/java/java/security/SignatureException.java
new file mode 100644
index 0000000..1b67037
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/SignatureException.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * This class represents generic security exceptions.
+ * 
+ */
+public class SignatureException extends GeneralSecurityException {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = 7509989324975124438L;
+
+    /**
+     * Constructs a new instance of this class with its walkback and message
+     * filled in.
+     * 
+     * 
+     * @param msg
+     *            String The detail message for the exception.
+     */
+    public SignatureException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a new instance of this class with its walkback filled in.
+     * 
+     */
+    public SignatureException() {
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public SignatureException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public SignatureException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/SignatureSpi.java b/libcore/security/src/main/java/java/security/SignatureSpi.java
new file mode 100644
index 0000000..f4623b6
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/SignatureSpi.java
@@ -0,0 +1,205 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+/**
+* @author Boris V. Kuznetsov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.nio.ByteBuffer;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public abstract class SignatureSpi {
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected SecureRandom appRandom;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected abstract void engineInitVerify(PublicKey publicKey)
+            throws InvalidKeyException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected abstract void engineInitSign(PrivateKey privateKey)
+            throws InvalidKeyException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
+            throws InvalidKeyException {
+        appRandom = random;
+        engineInitSign(privateKey);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected abstract void engineUpdate(byte b) throws SignatureException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected abstract void engineUpdate(byte[] b, int off, int len)
+            throws SignatureException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     * The SignatureException is not specified for this method. 
+     * So throw RuntimeException if underlying engineUpdate(byte[] b, int off, int len)
+     * throws SignatureException.
+     */
+    protected void engineUpdate(ByteBuffer input) {
+        if (!input.hasRemaining()) {
+            return;
+        }
+        byte[] tmp;
+        if (input.hasArray()) {
+            tmp = input.array();
+            int offset = input.arrayOffset();
+            int position = input.position();
+            int limit = input.limit();
+            try {
+                engineUpdate(tmp, offset + position, limit - position);
+            } catch (SignatureException e) { 
+                throw new RuntimeException(e); //Wrap SignatureException
+            }
+            input.position(limit);
+        } else {
+            tmp = new byte[input.limit() - input.position()];
+            input.get(tmp);
+            try {
+                engineUpdate(tmp, 0, tmp.length);
+            } catch (SignatureException e) {
+                throw new RuntimeException(e); //Wrap SignatureException
+            }
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected abstract byte[] engineSign() throws SignatureException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected int engineSign(byte[] outbuf, int offset, int len)
+            throws SignatureException {
+        byte tmp[] = engineSign();
+        if (tmp == null) {
+            return 0;
+        }
+        if (len < tmp.length) {
+            throw new SignatureException(Messages.getString("security.2D")); //$NON-NLS-1$
+        }
+        if (offset < 0) {
+            throw new SignatureException(Messages.getString("security.1C")); //$NON-NLS-1$
+        }
+        if (offset + len > outbuf.length) {
+            throw new SignatureException(Messages.getString("security.05")); //$NON-NLS-1$
+        }
+        System.arraycopy(tmp, 0, outbuf, offset, tmp.length);
+        return tmp.length;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected abstract boolean engineVerify(byte[] sigBytes)
+            throws SignatureException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected boolean engineVerify(byte[] sigBytes, int offset, int length)
+            throws SignatureException {
+        byte tmp[] = new byte[length];
+        System.arraycopy(sigBytes, offset, tmp, 0, length);
+        return engineVerify(tmp);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     * @deprecated Use
+     *             {@link SignatureSpi#engineSetParameter(AlgorithmParameterSpec) engineSetParameter}
+     */
+    protected abstract void engineSetParameter(String param, Object value)
+            throws InvalidParameterException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected void engineSetParameter(AlgorithmParameterSpec params)
+            throws InvalidAlgorithmParameterException {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected AlgorithmParameters engineGetParameters() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     * @deprecated There is no generally accepted parameter naming convention.
+     */
+    protected abstract Object engineGetParameter(String param)
+            throws InvalidParameterException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public Object clone() throws CloneNotSupportedException {
+        if (this instanceof Cloneable) {
+            return super.clone();
+        } else {
+            throw new CloneNotSupportedException();
+        }
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/SignedObject.java b/libcore/security/src/main/java/java/security/SignedObject.java
new file mode 100644
index 0000000..21f4547
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/SignedObject.java
@@ -0,0 +1,144 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris V. Kuznetsov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public final class SignedObject implements Serializable {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = 720502720485447167L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private byte[] content;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private byte[] signature;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private String thealgorithm;
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    private void readObject(ObjectInputStream s) throws IOException,
+            ClassNotFoundException {
+
+        s.defaultReadObject();
+        byte[] tmp = new byte[content.length];
+        System.arraycopy(content, 0, tmp, 0, content.length);
+        content = tmp;
+        tmp = new byte[signature.length];
+        System.arraycopy(signature, 0, tmp, 0, signature.length);
+        signature = tmp;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    public SignedObject(Serializable object, PrivateKey signingKey,
+            Signature signingEngine) throws IOException, InvalidKeyException,
+            SignatureException {
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(baos);
+        try {
+            // Serialize
+            oos.writeObject(object);
+            oos.flush();
+        } finally {
+            oos.close();
+        }
+        content = baos.toByteArray();
+        signingEngine.initSign(signingKey);
+        thealgorithm = signingEngine.getAlgorithm();
+        signingEngine.update(content);
+        signature = signingEngine.sign();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    public Object getObject() throws IOException, ClassNotFoundException {
+        // deserialize our object
+        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(
+                content));
+        try {
+            return ois.readObject();
+        } finally {
+            ois.close();
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    public byte[] getSignature() {
+        byte[] sig = new byte[signature.length];
+        System.arraycopy(signature, 0, sig, 0, signature.length);
+        return sig;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    public String getAlgorithm() {
+        return thealgorithm;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    public boolean verify(PublicKey verificationKey,
+            Signature verificationEngine) throws InvalidKeyException,
+            SignatureException {
+
+        verificationEngine.initVerify(verificationKey);
+        verificationEngine.update(content);
+        return verificationEngine.verify(signature);
+    }
+
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/Signer.java b/libcore/security/src/main/java/java/security/Signer.java
new file mode 100644
index 0000000..972c46e
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/Signer.java
@@ -0,0 +1,120 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Aleksei Y. Semenov
+ * @version $Revision$
+ */
+
+package java.security;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ * @deprecated Replaced by behavior in
+ *             {@link java.security.cert java.security.cert} package and
+ *             {@link java.security.Principal Principal}
+ */
+
+public abstract class Signer extends Identity {
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    private static final long serialVersionUID = -1763464102261361480L;
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    private PrivateKey privateKey;
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    protected Signer() {
+        super();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public Signer(String name) {
+        super(name);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public Signer(String name, IdentityScope scope)
+            throws KeyManagementException {
+        super(name, scope);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public PrivateKey getPrivateKey() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("getSignerPrivateKey"); //$NON-NLS-1$
+        }
+
+        return privateKey;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public final void setKeyPair(KeyPair pair)
+            throws InvalidParameterException, KeyException {
+        
+        if (pair == null) {
+            throw new NullPointerException();
+        }
+
+        if ((pair.getPrivate() == null) || (pair.getPublic() == null)) {
+            throw new InvalidParameterException();
+        }
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkSecurityAccess("setSignerKeyPair"); //$NON-NLS-1$
+        }
+        final PublicKey pk = pair.getPublic();
+        try {
+            AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
+                public Void run() throws KeyManagementException {
+                    setPublicKey(pk);
+                    return null;
+                }
+            });
+        } catch (PrivilegedActionException e) {
+            throw new KeyException(e.getException());
+        }
+        this.privateKey = pair.getPrivate();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public String toString() {
+        String s = "[Signer]" + getName(); //$NON-NLS-1$
+        if (getScope() != null) {
+            s = s + '[' + getScope().toString() + ']';
+        }
+        return s;
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/Timestamp.java b/libcore/security/src/main/java/java/security/Timestamp.java
new file mode 100644
index 0000000..b43441e
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/Timestamp.java
@@ -0,0 +1,113 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Astapchuk
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.security.cert.CertPath;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref 
+ */
+
+public final class Timestamp implements Serializable {
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    private static final long serialVersionUID = -5502683707821851294L;
+
+    private Date timestamp;
+
+    private CertPath signerCertPath;
+
+    // Cached hash
+    private transient int hash;
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public Timestamp(Date timestamp, CertPath signerCertPath) {
+        if (timestamp == null) {
+            throw new NullPointerException(Messages.getString("security.0F")); //$NON-NLS-1$
+        }
+        if (signerCertPath == null) {
+            throw new NullPointerException(Messages.getString("security.10")); //$NON-NLS-1$
+        }
+        // Clone timestamp to prevent modifications
+        this.timestamp = new Date(timestamp.getTime());
+        this.signerCertPath = signerCertPath;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj instanceof Timestamp) {
+            Timestamp that = (Timestamp) obj;
+            return timestamp.equals(that.timestamp)
+                    && signerCertPath.equals(that.signerCertPath);
+        }
+        return false;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public CertPath getSignerCertPath() {
+        return signerCertPath;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public Date getTimestamp() {
+        return timestamp;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public int hashCode() {
+        if (hash == 0) {
+            hash = timestamp.hashCode() ^ signerCertPath.hashCode();
+        }
+        return hash;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer(256);
+        // Dump only the first certificate
+        buf.append("Timestamp [").append(timestamp).append(" certPath="); //$NON-NLS-1$ //$NON-NLS-2$
+        buf.append(signerCertPath.getCertificates().get(0)).append("]"); //$NON-NLS-1$
+        return buf.toString();
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/UnrecoverableEntryException.java b/libcore/security/src/main/java/java/security/UnrecoverableEntryException.java
new file mode 100644
index 0000000..3c7d864
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/UnrecoverableEntryException.java
@@ -0,0 +1,48 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public class UnrecoverableEntryException extends GeneralSecurityException {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = -4527142945246286535L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public UnrecoverableEntryException() {
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public UnrecoverableEntryException(String msg) {
+        super(msg);
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/UnrecoverableKeyException.java b/libcore/security/src/main/java/java/security/UnrecoverableKeyException.java
new file mode 100644
index 0000000..2716e5e
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/UnrecoverableKeyException.java
@@ -0,0 +1,54 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security;
+
+/**
+ * This class represents exceptions if a key cannot be found in the keystore.
+ * 
+ */
+public class UnrecoverableKeyException extends GeneralSecurityException {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = 7275063078190151277L;
+
+    /**
+     * Constructs a new instance of this class with its walkback and message
+     * filled in.
+     * 
+     * 
+     * @param msg
+     *            String The detail message for the exception.
+     */
+    public UnrecoverableKeyException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a new instance of this class with its walkback filled in.
+     * 
+     */
+    public UnrecoverableKeyException() {
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/UnresolvedPermission.java b/libcore/security/src/main/java/java/security/UnresolvedPermission.java
new file mode 100644
index 0000000..83a089f
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/UnresolvedPermission.java
@@ -0,0 +1,370 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.io.Serializable;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.harmony.security.fortress.PolicyUtils;
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * Holds permissions which are of an unknown type when a policy file is read.
+ *
+ * Technically, the resolution of UnresolvedPermissions and
+ * substitution by actual permissions takes place in the
+ * <code>implies()</code> method of a <code>Permissions</code>
+ * collection, right before actual checking.
+ * 
+ */
+public final class UnresolvedPermission extends Permission
+    implements Serializable {
+
+    /** 
+     * @com.intel.drl.spec_ref 
+     */
+    private static final long serialVersionUID = -4821973115467008846L;
+
+    private static final ObjectStreamField serialPersistentFields[] = {
+        new ObjectStreamField("type", String.class), //$NON-NLS-1$
+        new ObjectStreamField("name", String.class), //$NON-NLS-1$
+        new ObjectStreamField("actions", String.class), }; //$NON-NLS-1$
+
+    // Target name
+    private transient String targetName;
+
+    //Target actions
+    private transient String targetActions;
+
+    // The signer certificates 
+    private transient Certificate[] targetCerts;
+
+    // Cached hash value
+    private transient int hash;
+
+    /**
+     * Constructs a new instance of this class with its type, name, and
+     * certificates set to the arguments by definition, actions are ignored
+     * 
+     * @param type
+     *            class of permission object
+     * @param name
+     *            identifies the permission that could not be resolved
+     * @param actions
+     * @param certs
+     */
+    public UnresolvedPermission(String type, String name, String actions,
+                                Certificate[] certs) {
+        super(type);
+        checkType(type);
+        targetName = name;
+        targetActions = actions;
+        if (certs != null && certs.length != 0) {
+            //TODO filter non-signer certificates ???
+            List tmp = new ArrayList();
+            for (int i = 0; i < certs.length; i++) {
+                if (certs[i] != null) {
+                    tmp.add(certs[i]);
+                }
+            }
+            if (tmp.size() != 0) {
+                targetCerts = (Certificate[])tmp.toArray(
+                                new Certificate[tmp.size()]);
+            }
+        }
+        hash = 0;
+    }
+
+    // Check type parameter
+    private final void checkType(String type) {
+        if (type == null) {
+            throw new NullPointerException(Messages.getString("security.2F")); //$NON-NLS-1$
+        }
+
+        // type is the class name of the Permission class.
+        // Empty string is inappropriate for class name.
+        // But this check is commented out for compatibility with RI.
+        // see JIRA issue HARMONY-733
+        // if (type.length() == 0) {
+        //     throw new IllegalArgumentException("type cannot be empty");
+        // }
+    }
+
+    /**
+     * Compares the argument to the receiver, and returns true if they represent
+     * the <em>same</em> object using a class specific comparison. In this
+     * case, the receiver and the object must have the same class, permission
+     * name, actions, and certificates
+     * 
+     * @param obj
+     *            the object to compare with this object
+     * @return <code>true</code> if the object is the same as this object,
+     *         <code>false</code> otherwise.
+     * 
+     * @see #hashCode
+     */
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj instanceof UnresolvedPermission) {
+            UnresolvedPermission that = (UnresolvedPermission)obj;
+            if (getName().equals(that.getName())
+                && (targetName == null ? that.targetName == null 
+                    : targetName.equals(that.targetName))
+                && (targetActions == null ? that.targetActions == null
+                    : targetActions.equals(that.targetActions))
+                && (PolicyUtils.matchSubset(targetCerts, that.targetCerts) 
+                    && PolicyUtils.matchSubset(that.targetCerts, targetCerts))) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns an integer hash code for the receiver. Any two objects which
+     * answer <code>true</code> when passed to <code>equals</code> must
+     * answer the same value for this method.
+     * 
+     * @return the receiver's hash
+     * 
+     * @see #equals
+     */
+    public int hashCode() {
+        if (hash == 0) {
+            hash = getName().hashCode();
+            if (targetName != null) {
+                hash ^= targetName.hashCode();
+            }
+            if (targetActions != null) {
+                hash ^= targetActions.hashCode();
+            }
+        }
+        return hash;
+    }
+
+    /**
+     * Returns the actions associated with the receiver. Since
+     * UnresolvedPermission objects have no actions, answer the empty string.
+     * 
+     * @return the actions associated with the receiver.
+     */
+    public String getActions() {
+        return ""; //$NON-NLS-1$
+    }
+
+    /** 
+     * @com.intel.drl.spec_ref 
+     */
+    public String getUnresolvedName() {
+        return targetName;
+    }
+
+    /** 
+     * @com.intel.drl.spec_ref 
+     */
+    public String getUnresolvedActions() {
+        return targetActions;
+    }
+
+    /** 
+     * @com.intel.drl.spec_ref 
+     */
+    public String getUnresolvedType() {
+        return super.getName();
+    }
+
+    /** 
+     * @com.intel.drl.spec_ref 
+     */
+    public Certificate[] getUnresolvedCerts() {
+        if (targetCerts != null) {
+            Certificate[] certs = new Certificate[targetCerts.length];
+            System.arraycopy(targetCerts, 0, certs, 0, certs.length);
+            return certs;
+        }
+        return null;
+    }
+
+    /**
+     * Indicates whether the argument permission is implied by the
+     * receiver.  UnresolvedPermission objects imply nothing
+     * because nothing is known about them yet.
+     * 
+         * Before actual implication checking, this method tries to
+         * resolve UnresolvedPermissions (if any) against the passed
+         * instance. Successfully resolved permissions (if any) are
+         * taken into account during further processing.
+         *
+     * @param permission
+     *            the permission to check
+     * @return always replies false
+     */
+    public boolean implies(Permission permission) {
+        return false;
+    }
+
+    /**
+     * Returns a string containing a concise, human-readable description of the
+     * receiver.
+     * 
+     * @return a printable representation for the receiver.
+     */
+    public String toString() {
+        return "(unresolved " + getName() + " " + targetName + " " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+            + targetActions + ")"; //$NON-NLS-1$
+    }
+
+    /**
+     * Returns a new PermissionCollection for holding permissions of this class.
+     * Answer null if any permission collection can be used.
+     * 
+     * @return a new PermissionCollection or null
+     * 
+     * @see java.security.BasicPermissionCollection
+     */
+    public PermissionCollection newPermissionCollection() {
+        return new UnresolvedPermissionCollection();
+    }
+
+    /**
+     * Tries to resolve this permission into the specified class. It is assumed
+     * that the class has a proper name (as returned by <code>getName()</code>
+     * of this unresolved permission), so no check is performed to verify this.
+     * However, the class must have all required certificates (as per
+     * <code>getUnresolvedCerts()</code>) among the passed collection of
+     * signers. If it does, a zero, one, and/or two-argument constructor is
+     * tried to instantiate a new permission, which is then returned. <br>
+     * If an appropriate constructor is not available or the class is
+     * improperly signed, <code>null</code> is returned.
+     * 
+     * @param targetType - a target class instance, must not be
+     *        <code>null</code>
+     * @param signers - actual signers of the targetType
+     * @return resolved permission or null
+     */
+    Permission resolve(Class targetType) {
+        // check signers at first
+        if (PolicyUtils.matchSubset(targetCerts, targetType.getSigners())) {
+            try {
+                return PolicyUtils.instantiatePermission(targetType,
+                                                         targetName,
+                                                         targetActions);
+            } catch (Exception ignore) {
+                //TODO log warning?
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     * Outputs <code>type</code>,<code>name</code>,<code>actions</code>
+     * fields via default mechanism; next manually writes certificates in the
+     * following format: <br>
+     *
+     * <ol>
+     * <li> int : number of certs or zero </li>
+     * <li> each cert in the following format
+     *     <ol>
+     *     <li> String : certificate type </li>
+     *     <li> int : length in bytes of certificate </li>
+     *     <li> byte[] : certificate encoding </li>
+     *     </ol>
+     * </li>
+     * </ol>
+     *
+     *  @see  <a href="http://java.sun.com/j2se/1.5.0/docs/api/serialized-form.html#java.security.UnresolvedPermission">Java Spec</a>
+     */
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        ObjectOutputStream.PutField fields = out.putFields();
+        fields.put("type", getUnresolvedType()); //$NON-NLS-1$
+        fields.put("name", getUnresolvedName()); //$NON-NLS-1$
+        fields.put("actions", getUnresolvedActions()); //$NON-NLS-1$
+        out.writeFields();
+        if (targetCerts == null) {
+            out.writeInt(0);
+        } else {
+            out.writeInt(targetCerts.length);
+            for (int i = 0; i < targetCerts.length; i++) {
+                try {
+                    byte[] enc = targetCerts[i].getEncoded();
+                    out.writeUTF(targetCerts[i].getType());
+                    out.writeInt(enc.length);
+                    out.write(enc);
+                } catch (CertificateEncodingException cee) {
+                    throw ((IOException)new NotSerializableException(
+                        Messages.getString("security.30",  //$NON-NLS-1$
+                        targetCerts[i])).initCause(cee));
+                }
+            }
+        }
+    }
+
+    /** 
+     * @com.intel.drl.spec_ref
+     * 
+     * Reads the object from stream and checks target type for validity. 
+     */
+    private void readObject(ObjectInputStream in) throws IOException,
+        ClassNotFoundException {
+        checkType(getUnresolvedType());
+        ObjectInputStream.GetField fields = in.readFields();
+        if (!getUnresolvedType().equals(fields.get("type", null))) { //$NON-NLS-1$
+            throw new InvalidObjectException(Messages.getString("security.31")); //$NON-NLS-1$
+        }
+        targetName = (String)fields.get("name", null); //$NON-NLS-1$
+        targetActions = (String)fields.get("actions", null); //$NON-NLS-1$
+        int certNumber = in.readInt();
+        if (certNumber != 0) {
+            targetCerts = new Certificate[certNumber];
+            for (int i = 0; i < certNumber; i++) {
+                try {
+                    String type = in.readUTF();
+                    int length = in.readInt();
+                    byte[] enc = new byte[length];
+                    in.readFully(enc, 0, length);
+                    targetCerts[i] = CertificateFactory.getInstance(type)
+                        .generateCertificate(new ByteArrayInputStream(enc));
+                } catch (CertificateException cee) {
+                    throw ((IOException)new IOException(
+                        Messages.getString("security.32")).initCause(cee)); //$NON-NLS-1$
+                }
+            }
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/UnresolvedPermissionCollection.java b/libcore/security/src/main/java/java/security/UnresolvedPermissionCollection.java
new file mode 100644
index 0000000..84c4467
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/UnresolvedPermissionCollection.java
@@ -0,0 +1,200 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package java.security;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Vector;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * Specific PermissionCollection for storing UnresolvedPermissions. Contained
+ * elements are grouped by their target type.
+ * 
+ */
+final class UnresolvedPermissionCollection extends PermissionCollection {
+
+    /** 
+     * @com.intel.drl.spec_ref 
+     */
+    private static final long serialVersionUID = -7176153071733132400L;
+
+    private static final ObjectStreamField[] serialPersistentFields = { 
+        new ObjectStreamField("permissions", Hashtable.class), }; //$NON-NLS-1$
+
+    // elements of the collection.
+    private transient Map klasses = new HashMap();
+
+    /**
+     * Adds an unresolved permission to the collection.
+     * 
+     * @see java.security.PermissionCollection#add(java.security.Permission)
+     */
+    public void add(Permission permission) {
+        if (isReadOnly()) {
+            throw new SecurityException(Messages.getString("security.15")); //$NON-NLS-1$
+        }
+        if (permission == null
+            || permission.getClass() != UnresolvedPermission.class) {
+            throw new IllegalArgumentException(Messages.getString("security.16", //$NON-NLS-1$
+                permission));
+        }
+        synchronized (klasses) {
+            String klass = permission.getName();
+            Collection klassMates = (Collection)klasses.get(klass);
+            if (klassMates == null) {
+                klassMates = new HashSet();
+                klasses.put(klass, klassMates);
+            }
+            klassMates.add(permission);
+        }
+    }
+
+    /**
+     * Returns enumeration over collection elements.
+     * 
+     * @see java.security.PermissionCollection#elements()
+     */
+    public Enumeration elements() {
+        Collection all = new ArrayList();
+        for (Iterator iter = klasses.values().iterator(); iter.hasNext();) {
+            all.addAll((Collection)iter.next());
+        }
+        return Collections.enumeration(all);
+    }
+
+    /**
+     * Always returns false.
+     * 
+     * @see java.security.UnresolvedPermission#implies(Permission)
+     */
+    public boolean implies(Permission permission) {
+        return false;
+    }
+    
+    /** 
+     * Returns true if this collection contains unresolved permissions 
+     * with the same classname as argument permission. 
+     */
+    boolean hasUnresolved(Permission permission) {
+        return klasses.containsKey(permission.getClass().getName());
+    }
+
+    /**
+     * Resolves all permissions of the same class as the specified target
+     * permission and adds them to the specified collection. If passed
+     * collection is <code>null</code> and some unresolved permissions were
+     * resolved, an appropriate new collection is instantiated and used. All
+     * resolved permissions are removed from this unresolved collection, and
+     * collection with resolved ones is returned.
+     * 
+     * @param target - a kind of permissions to be resolved
+     * @param holder - an existing collection for storing resolved permissions
+     * @return a collection containing resolved permissions (if any found)
+     */
+    PermissionCollection resolveCollection(Permission target,
+                                           PermissionCollection holder) {
+        String klass = target.getClass().getName();
+        if (klasses.containsKey(klass)) {
+            synchronized (klasses) {
+                Collection klassMates = (Collection)klasses.get(klass);
+                for (Iterator iter = klassMates.iterator(); iter.hasNext();) {
+                    UnresolvedPermission element = (UnresolvedPermission)iter
+                        .next();
+                    Permission resolved = element.resolve(target.getClass());
+                    if (resolved != null) {
+                        if (holder == null) {
+                            holder = target.newPermissionCollection();
+                            if (holder == null) {
+                                holder = new PermissionsHash();
+                            }
+                        }
+                        holder.add(resolved);
+                        iter.remove();
+                    }
+                }
+                if (klassMates.size() == 0) {
+                    klasses.remove(klass);
+                }
+            }
+        }
+        return holder;
+    }
+
+    /** 
+     * @com.intel.drl.spec_ref
+     * 
+     * Output fields via default mechanism. 
+     */
+    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
+        Hashtable permissions = new Hashtable();
+        for (Iterator iter = klasses.keySet().iterator(); iter.hasNext();) {
+            String key = (String)iter.next();
+            permissions.put(key, new Vector(((Collection)klasses.get(key))));
+        }
+        ObjectOutputStream.PutField fields = out.putFields();
+        fields.put("permissions", permissions); //$NON-NLS-1$
+        out.writeFields();
+    }
+
+    /** 
+     * @com.intel.drl.spec_ref
+     * 
+     * Reads the object from stream and checks elements grouping for validity. 
+     */
+    private void readObject(java.io.ObjectInputStream in) throws IOException,
+        ClassNotFoundException {
+        ObjectInputStream.GetField fields = in.readFields();
+        Map permissions = (Map)fields.get("permissions", null); //$NON-NLS-1$
+        klasses = new HashMap();
+        synchronized (klasses) {
+            for (Iterator iter = permissions.keySet().iterator(); iter
+                .hasNext();) {
+                String key = (String)iter.next();
+                Collection values = (Collection)permissions.get(key);
+                for (Iterator iterator = values.iterator(); iterator.hasNext();) {
+                    UnresolvedPermission element = (UnresolvedPermission)iterator
+                        .next();
+                    if (!element.getName().equals(key)) {
+                        throw new InvalidObjectException(
+                            Messages.getString("security.22")); //$NON-NLS-1$
+                    }
+                }
+                klasses.put(key, new HashSet(values));
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/acl/Acl.java b/libcore/security/src/main/java/java/security/acl/Acl.java
new file mode 100644
index 0000000..8a87a5e
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/acl/Acl.java
@@ -0,0 +1,75 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Aleksei Y. Semenov
+* @version $Revision$
+*/
+
+package java.security.acl;
+
+import java.security.Principal;
+import java.util.Enumeration;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ * 
+ */
+public interface Acl extends Owner {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    void setName(Principal caller, String name) throws NotOwnerException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    String getName();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    boolean addEntry(Principal caller, AclEntry entry) throws NotOwnerException;
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    boolean removeEntry(Principal caller, AclEntry entry) 
+                throws NotOwnerException;
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    Enumeration<Permission> getPermissions(Principal user); 
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    Enumeration<AclEntry> entries();
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    boolean checkPermission(Principal principal, Permission permission);
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    String toString();
+}
diff --git a/libcore/security/src/main/java/java/security/acl/AclEntry.java b/libcore/security/src/main/java/java/security/acl/AclEntry.java
new file mode 100644
index 0000000..5d0abcf
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/acl/AclEntry.java
@@ -0,0 +1,85 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Aleksei Y. Semenov
+* @version $Revision$
+*/
+
+package java.security.acl;
+
+import java.security.Principal;
+import java.util.Enumeration;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public interface AclEntry extends Cloneable {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    boolean setPrincipal(Principal user);
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    Principal getPrincipal();
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    void setNegativePermissions();
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    boolean isNegative();
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    boolean addPermission(Permission permission);
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    boolean removePermission(Permission permission);
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    boolean checkPermission(Permission permission);
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    Enumeration<Permission> permissions();
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    String toString();
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    Object clone();
+    
+}
diff --git a/libcore/security/src/main/java/java/security/acl/AclNotFoundException.java b/libcore/security/src/main/java/java/security/acl/AclNotFoundException.java
new file mode 100644
index 0000000..89dcea3
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/acl/AclNotFoundException.java
@@ -0,0 +1,42 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Astapchuk
+* @version $Revision$
+*/
+
+package java.security.acl;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public class AclNotFoundException extends Exception {
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    private static final long serialVersionUID = 5684295034092681791L;
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public AclNotFoundException() {
+
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/acl/Group.java b/libcore/security/src/main/java/java/security/acl/Group.java
new file mode 100644
index 0000000..37b3d5b
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/acl/Group.java
@@ -0,0 +1,55 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Aleksei Y. Semenov
+* @version $Revision$
+*/
+
+package java.security.acl;
+
+import java.security.Principal;
+import java.util.Enumeration;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public interface Group extends Principal {
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    boolean addMember(Principal user);
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    boolean removeMember(Principal user);
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    boolean isMember(Principal member);
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    Enumeration<? extends Principal> members();
+    
+}
diff --git a/libcore/security/src/main/java/java/security/acl/LastOwnerException.java b/libcore/security/src/main/java/java/security/acl/LastOwnerException.java
new file mode 100644
index 0000000..8ec328e
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/acl/LastOwnerException.java
@@ -0,0 +1,41 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Astapchuk
+* @version $Revision$
+*/
+
+package java.security.acl;
+
+/**
+ * @com.intel.drl.spec_ref
+ *  
+ */
+
+public class LastOwnerException extends Exception {
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    private static final long serialVersionUID = -5141997548211140359L;
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public LastOwnerException() {
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/acl/NotOwnerException.java b/libcore/security/src/main/java/java/security/acl/NotOwnerException.java
new file mode 100644
index 0000000..4681339
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/acl/NotOwnerException.java
@@ -0,0 +1,41 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Astapchuk
+* @version $Revision$
+*/
+
+package java.security.acl;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public class NotOwnerException extends Exception {
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    private static final long serialVersionUID = -5555597911163362399L;
+
+    /**
+     * @com.intel.drl.spec_ref 
+     */
+    public NotOwnerException() {
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/acl/Owner.java b/libcore/security/src/main/java/java/security/acl/Owner.java
new file mode 100644
index 0000000..5f604f7
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/acl/Owner.java
@@ -0,0 +1,50 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Aleksei Y. Semenov
+* @version $Revision$
+*/
+
+package java.security.acl;
+
+import java.security.Principal;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public interface Owner {
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    boolean addOwner(Principal caller, Principal owner) 
+                 throws NotOwnerException;
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    boolean deleteOwner(Principal caller, Principal owner) 
+                throws NotOwnerException, LastOwnerException;
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    boolean isOwner(Principal owner);
+}
diff --git a/libcore/security/src/main/java/java/security/acl/Permission.java b/libcore/security/src/main/java/java/security/acl/Permission.java
new file mode 100644
index 0000000..a9617bf
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/acl/Permission.java
@@ -0,0 +1,42 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Aleksei Y. Semenov
+* @version $Revision$
+*/
+
+package java.security.acl;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public interface Permission {
+
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    boolean equals(Object another);
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    String toString();
+}
diff --git a/libcore/security/src/main/java/java/security/acl/package.html b/libcore/security/src/main/java/java/security/acl/package.html
new file mode 100644
index 0000000..9d23cf9
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/acl/package.html
@@ -0,0 +1,14 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
+</head>
+<html>
+<body>
+<p>
+This package provides all the classes and all the interfaces needed to build Access Control List.
+Functionality for generating new entries in an ACL {@link java.security.acl.AclEntry};
+for the creation of new owner {@link java.security.acl.Owner} and for the registration of
+new permissions {@link java.security.acl.Permission} are provided.
+</p>
+</body>
+</html>
diff --git a/libcore/security/src/main/java/java/security/cert/CRL.java b/libcore/security/src/main/java/java/security/cert/CRL.java
new file mode 100644
index 0000000..74c0bf5
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CRL.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+/**
+ * This class represents Certificate Revocation Lists (CRLs). They are used to
+ * indicate that a given Certificate has expired already.
+ * 
+ * @see CertificateFactory
+ */
+public abstract class CRL {
+    // The CRL type
+    private final String type;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    protected CRL(String type) {
+        this.type = type;
+    }
+
+    /**
+     * Returns the type of this CRL.
+     * 
+     * @return String the type of this CRL.
+     */
+    public final String getType() {
+        return type;
+    }
+
+    /**
+     * Returns if a given Certificate has been revoked or not.
+     * 
+     * @param cert
+     *            Certificate The Certificate to test
+     * 
+     * @return true if the certificate has been revoked false if the certificate
+     *         has not been revoked yet
+     */
+    public abstract boolean isRevoked(Certificate cert);
+
+    /**
+     * Returns a string containing a concise, human-readable description of the
+     * receiver.
+     * 
+     * @return a printable representation for the receiver.
+     */
+    public abstract String toString();
+}
diff --git a/libcore/security/src/main/java/java/security/cert/CRLException.java b/libcore/security/src/main/java/java/security/cert/CRLException.java
new file mode 100644
index 0000000..e8ca9cb
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CRLException.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class CRLException extends GeneralSecurityException {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = -6694728944094197147L;
+
+    /**
+     * Constructs a new instance of this class with its walkback and message
+     * filled in.
+     * 
+     * @param msg
+     *            String The detail message for the exception.
+     */
+    public CRLException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a new instance of this class with its walkback filled in.
+     */
+    public CRLException() {
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CRLException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CRLException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/cert/CRLSelector.java b/libcore/security/src/main/java/java/security/cert/CRLSelector.java
new file mode 100644
index 0000000..c6e606e
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CRLSelector.java
@@ -0,0 +1,40 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface CRLSelector extends Cloneable {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Object clone();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public boolean match(CRL crl);
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/cert/CertPath.java b/libcore/security/src/main/java/java/security/cert/CertPath.java
new file mode 100644
index 0000000..6de5c09
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CertPath.java
@@ -0,0 +1,226 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.io.ByteArrayInputStream;
+import java.io.NotSerializableException;
+import java.io.ObjectStreamException;
+import java.io.ObjectStreamField;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * An immutable certificate path that can be validated. All certificates in the
+ * path are of the same type (i.e., X509).
+ * 
+ * A <code>CertPath</code> can be represented as a byte array in at least one
+ * supported encoding when serialized.
+ * 
+ * When a <code>List</code> of the certificates is obtained it must be
+ * immutable.
+ * 
+ * A <code>CertPath</code> must be thread-safe without requiring coordinated
+ * access.
+ */
+public abstract class CertPath implements Serializable {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = 6068470306649138683L;
+    // Standard name of the type of certificates in this path
+    private final String type;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    protected CertPath(String type) {
+        this.type = type;
+    }
+
+    /**
+     * Returns the type of <code>Certificate</code> in the
+     * <code>CertPath</code>
+     * 
+     * @return <code>Certificate</code> type
+     */
+    public String getType() {
+        return type;
+    }
+
+    /**
+     * Returns true if <code>Certificate</code>s in the list are the same
+     * type and the lists are equal (and by implication the certificates
+     * contained within are the same).
+     * 
+     * @param other
+     *            <code>CertPath</code> to be compared for equality
+     */
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+        if (other instanceof CertPath) {
+            CertPath o = (CertPath)other;
+            if (getType().equals(o.getType())) {
+                if (getCertificates().equals(o.getCertificates())) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Overrides Object.hashCode() Defined as: hashCode = 31 *
+     * path.getType().hashCode() + path.getCertificates().hashCode();
+     * 
+     * @return hash code for CertPath object
+     */
+    public int hashCode() {
+        int hash = getType().hashCode();
+        hash = hash*31 + getCertificates().hashCode();
+        return hash;
+    }
+
+    /**
+     * Returns a <code>String</code> representation of the
+     * <code>CertPath</code>
+     * <code>Certificate</code>s. It is the result of
+     * calling <code>toString</code> on all <code>Certificate</code>s in
+     * the <code>List</code>. <code>Certificate</code>s
+     * 
+     * @return string representation of <code>CertPath</code>
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer(getType());
+        sb.append(" Cert Path, len="); //$NON-NLS-1$
+        sb.append(getCertificates().size());
+        sb.append(": [\n"); //$NON-NLS-1$
+        int n=1;
+        for (Iterator i=getCertificates().iterator();
+                      i.hasNext(); n++) {
+            sb.append("---------------certificate "); //$NON-NLS-1$
+            sb.append(n);
+            sb.append("---------------\n"); //$NON-NLS-1$
+            sb.append(((Certificate)i.next()).toString());
+        }
+        sb.append("\n]"); //$NON-NLS-1$
+        return sb.toString();
+    }
+
+    /**
+     * Returns an immutable List of the <code>Certificate</code>s contained
+     * in the <code>CertPath</code>.
+     * 
+     * @return list of <code>Certificate</code>s in the <code>CertPath</code>
+     */
+    public abstract List<? extends Certificate> getCertificates();
+
+    /**
+     * Returns an encoding of the <code>CertPath</code> using the default
+     * encoding
+     * 
+     * @return default encoding of the <code>CertPath</code>
+     * @throws CertificateEncodingException
+     */
+    public abstract byte[] getEncoded()
+        throws CertificateEncodingException;
+
+    /**
+     * Returns an encoding of the <code>CertPath</code> using the specified
+     * encoding
+     * 
+     * @param encoding
+     *            encoding that should be generated
+     * @return default encoding of the <code>CertPath</code>
+     * @throws CertificateEncodingException
+     */
+    public abstract byte[] getEncoded(String encoding)
+        throws CertificateEncodingException;
+
+    /**
+     * Return an <code>Iterator</code> over the supported encodings for a
+     * representation of the certificate path.
+     * 
+     * @return <code>Iterator</code> over supported encodings (as
+     *         <code>String</code>s)
+     */
+    public abstract Iterator<String> getEncodings();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    protected Object writeReplace() throws ObjectStreamException {
+        try {
+            return new CertPathRep(getType(), getEncoded());
+        } catch (CertificateEncodingException e) {
+            throw new NotSerializableException (
+                    Messages.getString("security.66", e)); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    protected static class CertPathRep implements Serializable {
+        /**
+         * @com.intel.drl.spec_ref
+         */
+        private static final long serialVersionUID = 3015633072427920915L;
+        // Standard name of the type of certificates in this path
+        private final String type;
+        // cert path data
+        private final byte[] data;
+
+        // Force default serialization to use writeUnshared/readUnshared
+        // for cert path data
+        private static final ObjectStreamField[] serialPersistentFields = {
+             new ObjectStreamField("type", String.class), //$NON-NLS-1$
+             new ObjectStreamField("data", byte[].class, true) //$NON-NLS-1$
+        };
+
+        /**
+         * @com.intel.drl.spec_ref
+         */
+        protected CertPathRep(String type, byte[] data) {
+            this.type = type;
+            this.data = data;
+        }
+
+        /**
+         * @com.intel.drl.spec_ref
+         */
+        protected Object readResolve() throws ObjectStreamException {
+            try {
+                CertificateFactory cf = CertificateFactory.getInstance(type);
+                return cf.generateCertPath(new ByteArrayInputStream(data));
+            } catch (Throwable t) {
+                throw new NotSerializableException(
+                        Messages.getString("security.67", t)); //$NON-NLS-1$
+            }
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/cert/CertPathBuilder.java b/libcore/security/src/main/java/java/security/cert/CertPathBuilder.java
new file mode 100644
index 0000000..469cfcb
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CertPathBuilder.java
@@ -0,0 +1,170 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.security.AccessController;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.Security;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public class CertPathBuilder {
+
+    // Store CertPathBuilder service name
+    private static final String SERVICE = "CertPathBuilder"; //$NON-NLS-1$
+
+    // Used to access common engine functionality
+    private static Engine engine = new Engine(SERVICE);
+
+    // Store default property name
+    private static final String PROPERTYNAME = "certpathbuilder.type"; //$NON-NLS-1$
+
+    // Default value of CertPathBuilder type. It returns if certpathbuild.type
+    // property is not defined in java.security file
+    private static final String DEFAULTPROPERTY = "PKIX"; //$NON-NLS-1$
+
+    // Store used provider
+    private final Provider provider;
+
+    // Store spi implementation
+    private CertPathBuilderSpi spiImpl;
+
+    // Store algorithm name
+    private final String algorithm;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    protected CertPathBuilder(CertPathBuilderSpi builderSpi, Provider provider,
+            String algorithm) {
+        this.provider = provider;
+        this.algorithm = algorithm;
+        this.spiImpl = builderSpi;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public final String getAlgorithm() {
+        return algorithm;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public final Provider getProvider() {
+        return provider;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     * throws NullPointerException if algorithm is null (instead of
+     * NoSuchAlgorithmException as in 1.4 release)
+     */
+    public static CertPathBuilder getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        if (algorithm == null) {
+            throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+        }
+        synchronized (engine) {
+            engine.getInstance(algorithm, null);
+            return new CertPathBuilder((CertPathBuilderSpi) engine.spi,
+                    engine.provider, algorithm);
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     * throws NullPointerException if algorithm is null (instead of
+     * NoSuchAlgorithmException as in 1.4 release)
+     * 
+     * FIXME: jrockit-j2re1.4.2_04 throws IllegalArgumentException when provider
+     * is empty
+     */
+    public static CertPathBuilder getInstance(String algorithm, String provider)
+            throws NoSuchAlgorithmException, NoSuchProviderException {
+        if ((provider == null) || (provider.length() == 0)) {
+            throw new IllegalArgumentException(Messages.getString("security.02")); //$NON-NLS-1$
+        }
+        Provider impProvider = Security.getProvider(provider);
+        if (impProvider == null) {
+            throw new NoSuchProviderException(provider);
+        }
+        return getInstance(algorithm, impProvider);
+
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     * throws NullPointerException if algorithm is null (instead of
+     * NoSuchAlgorithmException as in 1.4 release)
+     */
+    public static CertPathBuilder getInstance(String algorithm,
+            Provider provider) throws NoSuchAlgorithmException {
+        if (provider == null) {
+            throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
+        }
+        if (algorithm == null) {
+            throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+        }
+        synchronized (engine) {
+            engine.getInstance(algorithm, provider, null);
+            return new CertPathBuilder((CertPathBuilderSpi) engine.spi, provider,
+                    algorithm);
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public final CertPathBuilderResult build(CertPathParameters params)
+            throws CertPathBuilderException, InvalidAlgorithmParameterException {
+        return spiImpl.engineBuild(params);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public static final String getDefaultType() {
+        String defaultType = AccessController
+                .doPrivileged(new java.security.PrivilegedAction<String>() {
+                    public String run() {
+                        return Security.getProperty(PROPERTYNAME);
+                    }
+                });
+        return (defaultType != null ? defaultType : DEFAULTPROPERTY);
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/cert/CertPathBuilderException.java b/libcore/security/src/main/java/java/security/cert/CertPathBuilderException.java
new file mode 100644
index 0000000..c064ceb
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CertPathBuilderException.java
@@ -0,0 +1,64 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class CertPathBuilderException extends GeneralSecurityException {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = 5316471420178794402L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CertPathBuilderException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CertPathBuilderException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CertPathBuilderException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CertPathBuilderException() {
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/cert/CertPathBuilderResult.java b/libcore/security/src/main/java/java/security/cert/CertPathBuilderResult.java
new file mode 100644
index 0000000..a8eff12
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CertPathBuilderResult.java
@@ -0,0 +1,40 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface CertPathBuilderResult extends Cloneable {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Object clone();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CertPath getCertPath();
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/cert/CertPathBuilderSpi.java b/libcore/security/src/main/java/java/security/cert/CertPathBuilderSpi.java
new file mode 100644
index 0000000..06adf0b
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CertPathBuilderSpi.java
@@ -0,0 +1,44 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.security.InvalidAlgorithmParameterException;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public abstract class CertPathBuilderSpi {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CertPathBuilderSpi() {
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract CertPathBuilderResult engineBuild(CertPathParameters params)
+            throws CertPathBuilderException, InvalidAlgorithmParameterException;
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/cert/CertPathParameters.java b/libcore/security/src/main/java/java/security/cert/CertPathParameters.java
new file mode 100644
index 0000000..d6dd330
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CertPathParameters.java
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface CertPathParameters extends Cloneable {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Object clone();
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/cert/CertPathValidator.java b/libcore/security/src/main/java/java/security/cert/CertPathValidator.java
new file mode 100644
index 0000000..683c968
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CertPathValidator.java
@@ -0,0 +1,169 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.security.AccessController;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.Security;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * <!-- @com.intel.drl.spec_ref -->
+ * 
+ */
+
+public class CertPathValidator {
+    // Store CertPathValidator implementation service name
+    private static final String SERVICE = "CertPathValidator"; //$NON-NLS-1$
+
+    // Used to access common engine functionality
+    private static Engine engine = new Engine(SERVICE);
+
+    // Store default property name
+    private static final String PROPERTYNAME = "certpathvalidator.type"; //$NON-NLS-1$
+
+    // Default value of CertPathBuilder type. It returns if certpathbuild.type
+    // property is not defined in java.security file
+    private static final String DEFAULTPROPERTY = "PKIX"; //$NON-NLS-1$
+
+    // Store used provider
+    private final Provider provider;
+
+    // Store used spi implementation
+    private final CertPathValidatorSpi spiImpl;
+
+    // Store used algorithm value
+    private final String algorithm;
+
+    /**
+     * <!-- @com.intel.drl.spec_ref -->
+     *  
+     */
+    protected CertPathValidator(CertPathValidatorSpi validatorSpi,
+            Provider provider, String algorithm) {
+        this.provider = provider;
+        this.algorithm = algorithm;
+        this.spiImpl = validatorSpi;
+    }
+
+    /**
+     * <!-- @com.intel.drl.spec_ref -->
+     *  
+     */
+    public final String getAlgorithm() {
+        return algorithm;
+    }
+
+    /**
+     * <!-- @com.intel.drl.spec_ref -->
+     *  
+     */
+    public final Provider getProvider() {
+        return provider;
+    }
+
+    /**
+     * <!-- @com.intel.drl.spec_ref -->
+     * 
+     * throws NullPointerException if algorithm is null
+     */
+    public static CertPathValidator getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        if (algorithm == null) {
+            throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+        }
+        synchronized (engine) {
+            engine.getInstance(algorithm, null);
+            return new CertPathValidator((CertPathValidatorSpi) engine.spi,
+                    engine.provider, algorithm);
+        }
+    }
+
+    /**
+     * <!-- @com.intel.drl.spec_ref -->
+     * 
+     * throws NullPointerException if algorithm is null
+     */
+    public static CertPathValidator getInstance(String algorithm,
+            String provider) throws NoSuchAlgorithmException,
+            NoSuchProviderException {
+        if ((provider == null) || (provider.length() == 0)) {
+            throw new IllegalArgumentException(Messages.getString("security.02")); //$NON-NLS-1$
+        }
+        Provider impProvider = Security.getProvider(provider);
+        if (impProvider == null) {
+            throw new NoSuchProviderException(provider);
+        }
+        return getInstance(algorithm, impProvider);
+    }
+
+    /**
+     * <!-- @com.intel.drl.spec_ref -->
+     * 
+     * throws NullPointerException if algorithm is null
+     */
+    public static CertPathValidator getInstance(String algorithm,
+            Provider provider) throws NoSuchAlgorithmException {
+        if (provider == null) {
+            throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
+        }
+        if (algorithm == null) {
+            throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+        }
+        synchronized (engine) {
+            engine.getInstance(algorithm, provider, null);
+            return new CertPathValidator((CertPathValidatorSpi) engine.spi,
+                    provider, algorithm);
+        }
+    }
+
+    /**
+     * <!-- @com.intel.drl.spec_ref -->
+     * 
+     */
+    public final CertPathValidatorResult validate(CertPath certPath,
+            CertPathParameters params) throws CertPathValidatorException,
+            InvalidAlgorithmParameterException {
+        return spiImpl.engineValidate(certPath, params);
+    }
+
+    /**
+     * <!-- @com.intel.drl.spec_ref -->
+     *  
+     */
+    public static final String getDefaultType() {
+        String defaultType = AccessController
+                .doPrivileged(new java.security.PrivilegedAction<String>() {
+                    public String run() {
+                        return Security.getProperty(PROPERTYNAME);
+                    }
+                });
+        return (defaultType != null ? defaultType : DEFAULTPROPERTY);
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/cert/CertPathValidatorException.java b/libcore/security/src/main/java/java/security/cert/CertPathValidatorException.java
new file mode 100644
index 0000000..18343a6
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CertPathValidatorException.java
@@ -0,0 +1,114 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.security.GeneralSecurityException;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class CertPathValidatorException extends GeneralSecurityException {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = -3083180014971893139L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     * Serialized field for storing certPath which is defined in constructor
+     * CertPathValidatorException(msg, cause, certPath, index)
+     */
+    private CertPath certPath;
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     * Serialized field for storing index which is defined in constructor
+     * CertPathValidatorException(msg, cause, certPath, index)
+     */
+    private int index = -1;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CertPathValidatorException(String msg, Throwable cause,
+            CertPath certPath, int index) {
+        super(msg, cause);
+        // check certPath and index parameters
+        if ((certPath == null) && (index != -1)) {
+            throw new IllegalArgumentException(
+                    Messages.getString("security.53")); //$NON-NLS-1$
+        }
+        if ((certPath != null)
+                && ((index < -1) || (index >= certPath.getCertificates().size()))) {
+            throw new IndexOutOfBoundsException(Messages.getString("security.54")); //$NON-NLS-1$
+        }
+        this.certPath = certPath;
+        this.index = index;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CertPathValidatorException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CertPathValidatorException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CertPathValidatorException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CertPathValidatorException() {
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CertPath getCertPath() {
+        return certPath;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public int getIndex() {
+        return index;
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/cert/CertPathValidatorResult.java b/libcore/security/src/main/java/java/security/cert/CertPathValidatorResult.java
new file mode 100644
index 0000000..ffbf353
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CertPathValidatorResult.java
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface CertPathValidatorResult extends Cloneable {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Object clone();
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/cert/CertPathValidatorSpi.java b/libcore/security/src/main/java/java/security/cert/CertPathValidatorSpi.java
new file mode 100644
index 0000000..abcfaed
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CertPathValidatorSpi.java
@@ -0,0 +1,47 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.security.InvalidAlgorithmParameterException;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public abstract class CertPathValidatorSpi {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CertPathValidatorSpi() {
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract CertPathValidatorResult engineValidate(CertPath certPath,
+            CertPathParameters params) throws CertPathValidatorException,
+            InvalidAlgorithmParameterException;
+
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/cert/CertSelector.java b/libcore/security/src/main/java/java/security/cert/CertSelector.java
new file mode 100644
index 0000000..cb0b9ec
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CertSelector.java
@@ -0,0 +1,40 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface CertSelector extends Cloneable {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Object clone();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public boolean match(Certificate cert);
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/cert/CertStore.java b/libcore/security/src/main/java/java/security/cert/CertStore.java
new file mode 100644
index 0000000..24b8b1a
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CertStore.java
@@ -0,0 +1,213 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.security.AccessController;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.Security;
+import java.util.Collection;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public class CertStore {
+
+    // Store spi implementation service name
+    private static final String SERVICE = "CertStore"; //$NON-NLS-1$
+
+    // Used to access common engine functionality
+    private static Engine engine = new Engine(SERVICE);
+
+    // Store default property name
+    private static final String PROPERTYNAME = "certstore.type"; //$NON-NLS-1$
+
+    // Default value of CertStore type. It returns if certpathbuild.type
+    // property is not defined in java.security file
+    private static final String DEFAULTPROPERTY = "LDAP"; //$NON-NLS-1$
+
+    // Store used provider
+    private final Provider provider;
+
+    // Store CertStoreSpi implementation
+    private final CertStoreSpi spiImpl;
+
+    // Store used type
+    private final String type;
+
+    // Store used parameters
+    private final CertStoreParameters certStoreParams;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    protected CertStore(CertStoreSpi storeSpi, Provider provider, String type,
+            CertStoreParameters params) {
+        this.provider = provider;
+        this.type = type;
+        this.spiImpl = storeSpi;
+        this.certStoreParams = params;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     * throws NullPointerException if type is null (instead of
+     * NoSuchAlgorithmException as in 1.4 release)
+     */
+    public static CertStore getInstance(String type, CertStoreParameters params)
+            throws InvalidAlgorithmParameterException, NoSuchAlgorithmException {
+        if (type == null) {
+            throw new NullPointerException(Messages.getString("security.07")); //$NON-NLS-1$
+        }
+        try {
+            synchronized (engine) {
+                engine.getInstance(type, params);
+                return new CertStore((CertStoreSpi) engine.spi, engine.provider,
+                        type, params);
+            }
+        } catch (NoSuchAlgorithmException e) {
+            Throwable th = e.getCause();
+            if (th == null) {
+                throw e;
+            } else {
+                throw new InvalidAlgorithmParameterException(e.getMessage(), th);
+            }
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     * throws NullPointerException if type is null (instead of
+     * NoSuchAlgorithmException as in 1.4 release)
+     * 
+     * FIXME: IllegalArgumentException when provider is empty
+     */
+    public static CertStore getInstance(String type,
+            CertStoreParameters params, String provider)
+            throws InvalidAlgorithmParameterException,
+            NoSuchAlgorithmException, NoSuchProviderException {
+        if ((provider == null) || (provider.length() == 0)) {
+            throw new IllegalArgumentException(Messages.getString("security.02")); //$NON-NLS-1$
+        }
+        Provider impProvider = Security.getProvider(provider);
+        if (impProvider == null) {
+            throw new NoSuchProviderException(provider);
+        }
+        return getInstance(type, params, impProvider);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     * throws NullPointerException if type is null (instead of
+     * NoSuchAlgorithmException as in 1.4 release)
+     */
+    public static CertStore getInstance(String type,
+            CertStoreParameters params, Provider provider)
+            throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
+        if (provider == null) {
+            throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
+        }
+        if (type == null) {
+            throw new NullPointerException(Messages.getString("security.07")); //$NON-NLS-1$
+        }
+        try {
+            synchronized (engine) {
+                engine.getInstance(type, provider, params);
+                return new CertStore((CertStoreSpi) engine.spi, provider, type,
+                        params);
+            }
+        } catch (NoSuchAlgorithmException e) {
+            Throwable th = e.getCause();
+            if (th == null) {
+                throw e;
+            } else {
+                throw new InvalidAlgorithmParameterException(e.getMessage(), th);
+            }
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public final String getType() {
+        return type;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public final Provider getProvider() {
+        return provider;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public final CertStoreParameters getCertStoreParameters() {
+        if (certStoreParams == null) {
+            return null;
+        } else {
+            return (CertStoreParameters) certStoreParams.clone();
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public final Collection<? extends Certificate> getCertificates(CertSelector selector)
+            throws CertStoreException {
+        return spiImpl.engineGetCertificates(selector);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public final Collection<? extends CRL> getCRLs(CRLSelector selector)
+            throws CertStoreException {
+        return spiImpl.engineGetCRLs(selector);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public static final String getDefaultType() {
+        String defaultType = AccessController
+                .doPrivileged(new java.security.PrivilegedAction<String>() {
+                    public String run() {
+                        return Security.getProperty(PROPERTYNAME);
+                    }
+                });
+        return (defaultType == null ? DEFAULTPROPERTY : defaultType);
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/cert/CertStoreException.java b/libcore/security/src/main/java/java/security/cert/CertStoreException.java
new file mode 100644
index 0000000..e8f14c3
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CertStoreException.java
@@ -0,0 +1,63 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class CertStoreException extends GeneralSecurityException {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = 2395296107471573245L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CertStoreException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CertStoreException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CertStoreException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CertStoreException() {
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/cert/CertStoreParameters.java b/libcore/security/src/main/java/java/security/cert/CertStoreParameters.java
new file mode 100644
index 0000000..34860b2
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CertStoreParameters.java
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface CertStoreParameters extends Cloneable {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Object clone();
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/cert/CertStoreSpi.java b/libcore/security/src/main/java/java/security/cert/CertStoreSpi.java
new file mode 100644
index 0000000..c1119d7
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CertStoreSpi.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.util.Collection;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public abstract class CertStoreSpi {
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     * Parameter 'params' is unusable but required by the spec
+     */
+    public CertStoreSpi(CertStoreParameters params)
+            throws InvalidAlgorithmParameterException {
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     * FIXME: 1.5 updated are needed Collection <? extends Certificate>
+     */
+    public abstract Collection<? extends Certificate> engineGetCertificates(CertSelector selector)
+            throws CertStoreException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     * FIXME: 1.5 updated are needed Collection <? extends CRL>
+     */
+    public abstract Collection<? extends CRL> engineGetCRLs(CRLSelector selector)
+            throws CertStoreException;
+}
diff --git a/libcore/security/src/main/java/java/security/cert/Certificate.java b/libcore/security/src/main/java/java/security/cert/Certificate.java
new file mode 100644
index 0000000..2508f31
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/Certificate.java
@@ -0,0 +1,249 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.io.ByteArrayInputStream;
+import java.io.NotSerializableException;
+import java.io.ObjectStreamException;
+import java.io.ObjectStreamField;
+import java.io.Serializable;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.util.Arrays;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * Abstract class to represent identity certificates. It represents a way to
+ * verify the binding of a Principal and its public key. Examples are X.509,
+ * PGP, and SDSI.
+ */
+public abstract class Certificate implements Serializable {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = -3585440601605666277L;
+
+    // The standard name of the certificate type
+    private final String type;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    protected Certificate(String type) {
+        this.type = type;
+    }
+
+    /**
+     * Returns the certificate type represented by the receiver.
+     * 
+     * @return the certificate type represented by the receiver.
+     */
+    public final String getType() {
+        return type;
+    }
+
+    /**
+     * Compares the argument to the receiver, and returns true if they represent
+     * the <em>same</em> object using a class specific comparison. The
+     * implementation in Object returns true only if the argument is the exact
+     * same object as the receiver (==).
+     * 
+     * @param other
+     *            the object to compare with this object
+     * @return <code>true</code> if the object is the same as this object
+     *         <code>false</code> if it is different from this object
+     * @see #hashCode
+     */
+    public boolean equals(Object other) {
+        // obj equal to itself
+        if (this == other) {
+            return true;
+        }
+        if (other instanceof Certificate) {
+            try {
+                // check that encoded forms match
+                return Arrays.equals(this.getEncoded(),
+                        ((Certificate)other).getEncoded());
+            } catch (CertificateEncodingException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns an integer hash code for the receiver. Any two objects which
+     * answer <code>true</code> when passed to <code>equals</code> must
+     * answer the same value for this method.
+     * 
+     * @return the receiver's hash
+     * 
+     * @see #equals
+     */
+    public int hashCode() {
+        try {
+            byte[] encoded = getEncoded();
+            int hash = 0;
+            for (int i=0; i<encoded.length; i++) {
+                hash += i*encoded[i];
+            }
+            return hash;
+        } catch (CertificateEncodingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Returns the encoded representation for this certificate.
+     * 
+     * @return the encoded representation for this certificate.
+     */
+    public abstract byte[] getEncoded() throws CertificateEncodingException;
+
+    /**
+     * Verifies that this certificate was signed with the given public key.
+     * 
+     * @param key
+     *            PublicKey public key for which verification should be
+     *            performed.
+     * 
+     * @exception CertificateException
+     *                if encoding errors are detected
+     * @exception NoSuchAlgorithmException
+     *                if an unsupported algorithm is detected
+     * @exception InvalidKeyException
+     *                if an invalid key is detected
+     * @exception NoSuchProviderException
+     *                if there is no default provider
+     * @exception SignatureException
+     *                if signature errors are detected
+     */
+    public abstract void verify(PublicKey key)
+        throws CertificateException,
+               NoSuchAlgorithmException,
+               InvalidKeyException,
+               NoSuchProviderException,
+               SignatureException;
+
+    /**
+     * Verifies that this certificate was signed with the given public key. Uses
+     * the signature algorithm given by the provider.
+     * 
+     * @param key
+     *            PublicKey public key for which verification should be
+     *            performed.
+     * @param sigProvider
+     *            String the name of the signature provider.
+     * 
+     * @exception CertificateException
+     *                if encoding errors are detected
+     * @exception NoSuchAlgorithmException
+     *                if an unsupported algorithm is detected
+     * @exception InvalidKeyException
+     *                if an invalid key is detected
+     * @exception NoSuchProviderException
+     *                if there is no default provider
+     * @exception SignatureException
+     *                if signature errors are detected
+     */
+    public abstract void verify(PublicKey key, String sigProvider)
+        throws CertificateException,
+               NoSuchAlgorithmException,
+               InvalidKeyException,
+               NoSuchProviderException,
+               SignatureException;
+
+    /**
+     * Returns a string containing a concise, human-readable description of the
+     * receiver.
+     * 
+     * @return a printable representation for the receiver.
+     */
+    public abstract String toString();
+
+    /**
+     * Returns the public key corresponding to this certificate.
+     * 
+     * @return the public key corresponding to this certificate.
+     */
+    public abstract PublicKey getPublicKey();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    protected Object writeReplace() throws ObjectStreamException {
+        try {
+            return new CertificateRep(getType(), getEncoded());
+        } catch (CertificateEncodingException e) {  
+            throw new NotSerializableException (
+                    Messages.getString("security.66", e)); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     */
+    protected static class CertificateRep implements Serializable {
+        /**
+         * @com.intel.drl.spec_ref
+         */
+        private static final long serialVersionUID = -8563758940495660020L;
+        // The standard name of the certificate type
+        private final String type;
+        // The certificate data
+        private final byte[] data;
+
+        // Force default serialization to use writeUnshared/readUnshared
+        // for the certificate data
+        private static final ObjectStreamField[] serialPersistentFields = {
+             new ObjectStreamField("type", String.class), //$NON-NLS-1$
+             new ObjectStreamField("data", byte[].class, true) //$NON-NLS-1$
+        };
+
+        /**
+         * @com.intel.drl.spec_ref
+         */
+        protected CertificateRep(String type, byte[] data) {
+            this.type = type;
+            this.data = data;
+        }
+
+        /**
+         * @com.intel.drl.spec_ref
+         */
+        protected Object readResolve() throws ObjectStreamException {
+            try {
+                CertificateFactory cf = CertificateFactory.getInstance(type);
+                return cf.generateCertificate(new ByteArrayInputStream(data));
+            } catch (Throwable t) {
+                throw new NotSerializableException(
+                        Messages.getString("security.68", t)); //$NON-NLS-1$
+            }
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/cert/CertificateEncodingException.java b/libcore/security/src/main/java/java/security/cert/CertificateEncodingException.java
new file mode 100644
index 0000000..089f487
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CertificateEncodingException.java
@@ -0,0 +1,66 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+/**
+ * This class represents an encoding exception for a certificate.
+ */
+public class CertificateEncodingException extends CertificateException {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = 6219492851589449162L;
+
+    /**
+     * Constructs a new instance of this class with its walkback and message
+     * filled in.
+     * 
+     * @param msg
+     *            String The detail message for the exception.
+     */
+    public CertificateEncodingException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a new instance of this class with its walkback filled in.
+     */
+    public CertificateEncodingException() {
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public CertificateEncodingException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public CertificateEncodingException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/cert/CertificateException.java b/libcore/security/src/main/java/java/security/cert/CertificateException.java
new file mode 100644
index 0000000..c36512c
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CertificateException.java
@@ -0,0 +1,70 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * This class represents a general certificate exception.
+ */
+public class CertificateException extends GeneralSecurityException {
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    private static final long serialVersionUID = 3192535253797119798L;
+
+    /**
+     * Constructs a new instance of this class with its walkback and message
+     * filled in.
+     * 
+     * @param msg
+     *            String The detail message for the exception.
+     */
+    public CertificateException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a new instance of this class with its walkback filled in.
+     */
+    public CertificateException() {
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public CertificateException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public CertificateException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/cert/CertificateExpiredException.java b/libcore/security/src/main/java/java/security/cert/CertificateExpiredException.java
new file mode 100644
index 0000000..b3549a2
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CertificateExpiredException.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+/**
+ * This class indicates that a given certificate has expired.
+ */
+public class CertificateExpiredException extends CertificateException {
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    private static final long serialVersionUID = 9071001339691533771L;
+
+    /**
+     * Constructs a new instance of this class with its walkback and message
+     * filled in.
+     * 
+     * @param msg
+     *            String The detail message for the exception.
+     */
+    public CertificateExpiredException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a new instance of this class with its walkback filled in.
+     */
+    public CertificateExpiredException() {
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/cert/CertificateFactory.java b/libcore/security/src/main/java/java/security/cert/CertificateFactory.java
new file mode 100644
index 0000000..746b251
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CertificateFactory.java
@@ -0,0 +1,314 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.io.InputStream;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.Security;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.harmony.security.fortress.Engine;
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * This class provides the functionality of a certificate factory algorithm.
+ */
+
+public class CertificateFactory {
+
+    // Store CertificateFactory service name
+    private static final String SERVICE = "CertificateFactory"; //$NON-NLS-1$
+
+    // Used to access common engine functionality
+    private static Engine engine = new Engine(SERVICE);
+
+    // Store used provider
+    private final Provider provider;
+
+    // Store used CertificateFactorySpi implementation
+    private final CertificateFactorySpi spiImpl;
+
+    // Store used type
+    private final String type;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    protected CertificateFactory(CertificateFactorySpi certFacSpi,
+            Provider provider, String type) {
+        this.provider = provider;
+        this.type = type;
+        this.spiImpl = certFacSpi;
+    }
+
+    /**
+     * Returns a new CertificateFactory of the given type.
+     * 
+     * @param type
+     *            java.lang.String Type of certificate desired
+     * @return CertificateFactory a concrete implementation for the certificate
+     *         type desired.
+     * 
+     * @exception CertificateException
+     *                If the type cannot be found
+     *
+     * @exception NullPointerException
+     *                If the type is null
+     */
+    public static final CertificateFactory getInstance(String type)
+            throws CertificateException {
+        if (type == null) {
+            throw new NullPointerException(Messages.getString("security.07")); //$NON-NLS-1$
+        }
+        try {
+            synchronized (engine) {
+                engine.getInstance(type, null);
+                return new CertificateFactory((CertificateFactorySpi) engine.spi,
+                        engine.provider, type);
+            }
+        } catch (NoSuchAlgorithmException e) {
+            throw new CertificateException(e);
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     * 
+     * throws NullPointerException if algorithm is null (instead of
+     * CertificateException as in 1.4 release)
+     */
+    public static final CertificateFactory getInstance(String type,
+            String provider) throws CertificateException,
+            NoSuchProviderException {
+        if ((provider == null) || (provider.length() == 0)) {
+            throw new IllegalArgumentException(Messages.getString("security.02")); //$NON-NLS-1$
+        }
+        Provider impProvider = Security.getProvider(provider);
+        if (impProvider == null) {
+            throw new NoSuchProviderException(provider);
+        }
+        return getInstance(type, impProvider);
+    }
+
+    /**
+     * Returns a new CertificateFactory of the given type.
+     * 
+     * @param type
+     *            java.lang.String Type of certificate desired
+     * @param provider
+     *            java.security.Provider Provider which has to implement the
+     *            algorithm
+     * @return CertificateFactory a concrete implementation for the certificate
+     *         type desired.
+     * 
+     * @exception CertificateException
+     *                If the type cannot be found
+     *
+     * @exception NullPointerException
+     *                If algorithm is null
+     */
+    public static final CertificateFactory getInstance(String type,
+            Provider provider) throws CertificateException {
+        if (provider == null) {
+            throw new IllegalArgumentException(Messages.getString("security.04")); //$NON-NLS-1$
+        }
+        if (type == null) {
+            throw new NullPointerException(Messages.getString("security.07")); //$NON-NLS-1$
+        }
+        try {
+            synchronized (engine) {
+                engine.getInstance(type, provider, null);
+                return new CertificateFactory((CertificateFactorySpi) engine.spi,
+                        provider, type);
+            }
+        } catch (NoSuchAlgorithmException e) {
+            throw new CertificateException(e.getMessage());
+        }
+    }
+
+    /**
+     * Returns the Provider of the certificate factory represented by the
+     * receiver.
+     * 
+     * @return Provider an instance of a subclass of java.security.Provider
+     */
+    public final Provider getProvider() {
+        return provider;
+    }
+
+    /**
+     * Returns the Certificate type
+     * 
+     * @return String type of certificate being used
+     */
+    public final String getType() {
+        return type;
+    }
+
+    /**
+     * Generates and initializes a Certificate from data from the
+     * provided input stream.
+     * 
+     * @param inStream
+     *            InputStream Stream from where data is read to create the
+     *            Certificate
+     * 
+     * @return Certificate an initialized Certificate
+     * @exception CertificateException
+     *                if parsing problems are detected
+     */
+    public final Certificate generateCertificate(InputStream inStream)
+            throws CertificateException {
+        return spiImpl.engineGenerateCertificate(inStream);
+    }
+
+    /**
+     * Returns an Iterator over the supported CertPath encodings (as Strings).
+     * The first element is the default encoding.
+     * 
+     * @return Iterator Iterator over supported CertPath encodings (as Strings)
+     */
+    public final Iterator<String> getCertPathEncodings() {
+        return spiImpl.engineGetCertPathEncodings();
+    }
+
+    /**
+     * Generates a <code>CertPath</code> from data from the provided
+     * <code>InputStream</code>. The default encoding is assumed.
+     * 
+     * @param inStream
+     *            InputStream with PKCS7 or PkiPath encoded data
+     * 
+     * @return CertPath a CertPath initialized from the provided data
+     * 
+     * @throws CertificateException
+     *             if parsing problems are detected
+     */
+    public final CertPath generateCertPath(InputStream inStream)
+            throws CertificateException {
+        Iterator it = getCertPathEncodings();
+        if (!it.hasNext()) {
+            throw new CertificateException(Messages.getString("security.74")); //$NON-NLS-1$
+        }
+        return spiImpl.engineGenerateCertPath(inStream, (String) it.next());
+    }
+
+    /**
+     * Generates a <code>CertPath</code> from data from the provided
+     * <code>InputStream</code>. The encoding is that specified by the
+     * encoding parameter.
+     * 
+     * @param inStream
+     *            InputStream containing certificate path data in specified
+     *            encoding
+     * @param encoding
+     *            encoding of the data in the input stream
+     * 
+     * @return CertPath a CertPath initialized from the provided data
+     * 
+     * @throws CertificateException
+     *             if parsing problems are detected
+     * @throws UnsupportedOperationException
+     *             if the provider does not implement this method
+     */
+    public final CertPath generateCertPath(InputStream inStream, String encoding)
+            throws CertificateException {
+        return spiImpl.engineGenerateCertPath(inStream, encoding);
+    }
+
+    /**
+     * Generates a <code>CertPath</code> from the provided List of
+     * Certificates. The encoding is the default encoding.
+     * 
+     * @param certificates
+     *            List containing certificates in a format supported by the
+     *            CertificateFactory
+     * 
+     * @return CertPath a CertPath initialized from the provided data
+     * 
+     * @throws CertificateException
+     *             if parsing problems are detected
+     * @throws UnsupportedOperationException
+     *             if the provider does not implement this method
+     */
+    public final CertPath generateCertPath(List<? extends Certificate> certificates)
+            throws CertificateException {
+        return spiImpl.engineGenerateCertPath(certificates);
+    }
+
+    /**
+     * Generates and initializes a collection of Certificates from
+     * data from the provided input stream.
+     * 
+     * @param inStream
+     *            InputStream Stream from where data is read to create the
+     *            Certificates
+     * 
+     * @return Collection an initialized collection of Certificates
+     * @exception CertificateException
+     *                if parsing problems are detected
+     */
+    public final Collection<? extends Certificate> generateCertificates(InputStream inStream)
+            throws CertificateException {
+        return spiImpl.engineGenerateCertificates(inStream);
+    }
+
+    /**
+     * Generates and initializes a Certificate Revocation List from data from
+     * the provided input stream.
+     * 
+     * @param inStream
+     *            InputStream Stream from where data is read to create the CRL
+     * 
+     * @return CRL an initialized Certificate Revocation List
+     * @exception CRLException
+     *                if parsing problems are detected
+     */
+    public final CRL generateCRL(InputStream inStream) throws CRLException {
+        return spiImpl.engineGenerateCRL(inStream);
+    }
+
+    /**
+     * Generates and initializes a collection of Certificate Revocation List
+     * from data from the provided input stream.
+     * 
+     * @param inStream
+     *            InputStream Stream from where data is read to create the CRLs
+     * 
+     * @return Collection an initialized collection of Certificate Revocation
+     *         List
+     * @exception CRLException
+     *                if parsing problems are detected
+     * 
+     */
+    public final Collection<? extends CRL> generateCRLs(InputStream inStream)
+            throws CRLException {
+        return spiImpl.engineGenerateCRLs(inStream);
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/cert/CertificateFactorySpi.java b/libcore/security/src/main/java/java/security/cert/CertificateFactorySpi.java
new file mode 100644
index 0000000..d0f6ec6
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CertificateFactorySpi.java
@@ -0,0 +1,177 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * This class is a Service Provider Interface (therefore the Spi suffix) for
+ * certificate factories to be supplied by providers.
+ */
+
+public abstract class CertificateFactorySpi {
+
+    /**
+     * Constructs a new instance of this class.
+     */
+    public CertificateFactorySpi() {
+    }
+
+    /**
+     * Generates and initializes a Certificate from data from the
+     * provided input stream.
+     * 
+     * @param inStream
+     *            InputStream Stream from where data is read to create the
+     *            Certificate
+     * 
+     * @return Certificate an initialized Certificate
+     * @exception CertificateException
+     *                if parsing problems are detected
+     */
+    public abstract Certificate engineGenerateCertificate(InputStream inStream)
+            throws CertificateException;
+
+    /**
+     * Generates and initializes a collection of Certificates from
+     * data from the provided input stream.
+     * 
+     * @param inStream
+     *            InputStream Stream from where data is read to create the
+     *            Certificates
+     * 
+     * @return Collection an initialized collection of Certificates
+     * @exception CertificateException
+     *                if parsing problems are detected
+     */
+    public abstract Collection<? extends Certificate> 
+        engineGenerateCertificates(InputStream inStream) throws CertificateException;
+
+    /**
+     * Generates and initializes a Certificate Revocation List from data from
+     * the provided input stream.
+     * 
+     * @param inStream
+     *            InputStream Stream from where data is read to create the CRL
+     * 
+     * @return CRL an initialized Certificate Revocation List
+     * @exception CRLException
+     *                if parsing problems are detected
+     */
+    public abstract CRL engineGenerateCRL(InputStream inStream)
+            throws CRLException;
+
+    /**
+     * Generates and initializes a collection of Certificate Revocation List
+     * from data from the provided input stream.
+     * 
+     * @param inStream
+     *            InputStream Stream from where data is read to create the CRLs
+     * 
+     * @return Collection an initialized collection of Certificate Revocation
+     *         List
+     * @exception CRLException
+     *                if parsing problems are detected
+     */
+    public abstract Collection<? extends CRL> 
+        engineGenerateCRLs(InputStream inStream) throws CRLException;
+
+    /**
+     * Generates a <code>CertPath</code> from data from the provided
+     * <code>InputStream</code>. The default encoding is assumed.
+     * 
+     * @param inStream
+     *            InputStream with PKCS7 or PkiPath encoded data
+     * 
+     * @return CertPath a CertPath initialized from the provided data
+     * 
+     * @throws CertificateException
+     *             if parsing problems are detected
+     */
+    public CertPath engineGenerateCertPath(InputStream inStream)
+            throws CertificateException {
+        throw new UnsupportedOperationException(
+                Messages.getString("security.70")); //$NON-NLS-1$
+    }
+
+    /**
+     * Generates a <code>CertPath</code> from data from the provided
+     * <code>InputStream</code>. The encoding is that specified by the
+     * encoding parameter.
+     * 
+     * @param inStream
+     *            InputStream containing certificate path data in specified
+     *            encoding
+     * @param encoding
+     *            encoding of the data in the input stream
+     * 
+     * @return CertPath a CertPath initialized from the provided data
+     * 
+     * @throws CertificateException
+     *             if parsing problems are detected
+     * @throws UnsupportedOperationException
+     *             if the provider does not implement this method
+     */
+    public CertPath engineGenerateCertPath(InputStream inStream, String encoding)
+            throws CertificateException {
+        throw new UnsupportedOperationException(
+                Messages.getString("security.71")); //$NON-NLS-1$
+    }
+
+    /**
+     * Generates a <code>CertPath</code> from the provided List of
+     * Certificates. The encoding is the default encoding.
+     * 
+     * @param certificates
+     *            List containing certificates in a format supported by the
+     *            CertificateFactory
+     * 
+     * @return CertPath a CertPath initialized from the provided data
+     * 
+     * @throws CertificateException
+     *             if parsing problems are detected
+     * @throws UnsupportedOperationException
+     *             if the provider does not implement this method
+     */
+    public CertPath engineGenerateCertPath(List<? extends Certificate>  certificates) 
+            throws CertificateException {
+        throw new UnsupportedOperationException(
+                Messages.getString("security.72")); //$NON-NLS-1$
+    }
+
+    /**
+     * Returns an Iterator over the supported CertPath encodings (as Strings).
+     * The first element is the default encoding.
+     * 
+     * @return Iterator Iterator over supported CertPath encodings (as Strings)
+     */
+    public Iterator<String> engineGetCertPathEncodings() {
+        throw new UnsupportedOperationException(
+                Messages.getString("security.73")); //$NON-NLS-1$
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/cert/CertificateNotYetValidException.java b/libcore/security/src/main/java/java/security/cert/CertificateNotYetValidException.java
new file mode 100644
index 0000000..673a729
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CertificateNotYetValidException.java
@@ -0,0 +1,50 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+/**
+ * This class indicates that a given certificate is not valid yet.
+ */
+public class CertificateNotYetValidException extends CertificateException {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = 4355919900041064702L;
+
+    /**
+     * Constructs a new instance of this class with its walkback and message
+     * filled in.
+     * 
+     * @param msg
+     *            String The detail message for the exception.
+     */
+    public CertificateNotYetValidException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a new instance of this class with its walkback filled in.
+     */
+    public CertificateNotYetValidException() {
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/cert/CertificateParsingException.java b/libcore/security/src/main/java/java/security/cert/CertificateParsingException.java
new file mode 100644
index 0000000..d985944
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CertificateParsingException.java
@@ -0,0 +1,65 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+/**
+ * This class indicates that a given certificate could not be parsed.
+ */
+public class CertificateParsingException extends CertificateException {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = -7989222416793322029L;
+
+    /**
+     * Constructs a new instance of this class with its walkback and message
+     * filled in.
+     * 
+     * @param msg
+     *            String The detail message for the exception.
+     */
+    public CertificateParsingException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a new instance of this class with its walkback filled in.
+     */
+    public CertificateParsingException() {
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CertificateParsingException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CertificateParsingException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/cert/CollectionCertStoreParameters.java b/libcore/security/src/main/java/java/security/cert/CollectionCertStoreParameters.java
new file mode 100644
index 0000000..0ded19c
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/CollectionCertStoreParameters.java
@@ -0,0 +1,82 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class CollectionCertStoreParameters implements CertStoreParameters {
+    // Default empty and immutable collection.
+    // Used if <code>CollectionCertStoreParameters</code>instance
+    // created by the no arg constructor
+    private static final Collection defaultCollection = Collections.EMPTY_SET;
+    // A <code>Collection</code> of <code>Certificate</code>s
+    // and <code>CRL</code>s
+    private final Collection collection;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CollectionCertStoreParameters() {
+        this.collection = defaultCollection;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CollectionCertStoreParameters(Collection<?> collection) {
+        this.collection = collection;
+        if (this.collection == null) {
+            throw new NullPointerException();
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Object clone() {
+        return new CollectionCertStoreParameters(collection);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Collection<?> getCollection() {
+        return collection;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public String toString() {
+        StringBuffer sb =
+            new StringBuffer("CollectionCertStoreParameters: [\ncollection: "); //$NON-NLS-1$
+        sb.append(getCollection().toString());
+        sb.append("\n]"); //$NON-NLS-1$
+        return sb.toString();
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/cert/LDAPCertStoreParameters.java b/libcore/security/src/main/java/java/security/cert/LDAPCertStoreParameters.java
new file mode 100644
index 0000000..d965c42
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/LDAPCertStoreParameters.java
@@ -0,0 +1,103 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class LDAPCertStoreParameters implements CertStoreParameters {
+    // Default LDAP server name
+    private static final String DEFAULT_LDAP_SERVER_NAME = "localhost"; //$NON-NLS-1$
+    // Default LDAP server port number 
+    private static final int DEFAULT_LDAP_PORT  = 389;
+
+    // LDAP server name for this cert store
+    private final String serverName;
+    // LDAP server port number for this cert store
+    private final int port;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public LDAPCertStoreParameters(String serverName, int port) {
+        this.port = port;
+        this.serverName = serverName;
+        if (this.serverName == null) {
+            throw new NullPointerException();
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public LDAPCertStoreParameters() {
+        this.serverName = DEFAULT_LDAP_SERVER_NAME;
+        this.port = DEFAULT_LDAP_PORT;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public LDAPCertStoreParameters(String serverName) {
+        this.port = DEFAULT_LDAP_PORT;
+        this.serverName = serverName;
+        if (this.serverName == null) {
+            throw new NullPointerException();
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Object clone() {
+        return new LDAPCertStoreParameters(serverName, port);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public int getPort() {
+        return port;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public String getServerName() {
+        return serverName;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public String toString() {
+        StringBuffer sb =
+            new StringBuffer("LDAPCertStoreParameters: [\n serverName: "); //$NON-NLS-1$
+        sb.append(getServerName());
+        sb.append("\n port: "); //$NON-NLS-1$
+        sb.append(getPort());
+        sb.append("\n]"); //$NON-NLS-1$
+        return sb.toString();
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/cert/PKIXBuilderParameters.java b/libcore/security/src/main/java/java/security/cert/PKIXBuilderParameters.java
new file mode 100644
index 0000000..c6df05a
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/PKIXBuilderParameters.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.util.Set;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class PKIXBuilderParameters extends PKIXParameters {
+    // Maximum certificate path length (5 by default)
+    private int maxPathLength = 5;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public PKIXBuilderParameters(Set<TrustAnchor> trustAnchors,
+            CertSelector targetConstraints)
+        throws InvalidAlgorithmParameterException {
+        super(trustAnchors);
+        super.setTargetCertConstraints(targetConstraints);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public PKIXBuilderParameters(KeyStore keyStore,
+            CertSelector targetConstraints)
+        throws KeyStoreException,
+               InvalidAlgorithmParameterException {
+        super(keyStore);
+        super.setTargetCertConstraints(targetConstraints);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public int getMaxPathLength() {
+        return maxPathLength;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setMaxPathLength(int maxPathLength) {
+        if (maxPathLength < -1) {
+            throw new InvalidParameterException(
+                    Messages.getString("security.5B")); //$NON-NLS-1$
+        }
+        this.maxPathLength = maxPathLength;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer("[\n"); //$NON-NLS-1$
+        sb.append(super.toString());
+        sb.append(" Max Path Length: "); //$NON-NLS-1$
+        sb.append(maxPathLength);
+        sb.append("\n]"); //$NON-NLS-1$
+        return sb.toString();
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/cert/PKIXCertPathBuilderResult.java b/libcore/security/src/main/java/java/security/cert/PKIXCertPathBuilderResult.java
new file mode 100644
index 0000000..d0a34ba
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/PKIXCertPathBuilderResult.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.security.PublicKey;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class PKIXCertPathBuilderResult extends PKIXCertPathValidatorResult
+        implements CertPathBuilderResult {
+    // Built and validated certification path
+    private final CertPath certPath;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public PKIXCertPathBuilderResult(CertPath certPath, TrustAnchor trustAnchor,
+            PolicyNode policyTree, PublicKey subjectPublicKey) {
+        super(trustAnchor, policyTree, subjectPublicKey);
+        this.certPath = certPath;
+        if (this.certPath == null) {
+            throw new NullPointerException(Messages.getString("security.55")); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CertPath getCertPath() {
+        return certPath;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer(super.toString());
+        sb.append("\n Certification Path: "); //$NON-NLS-1$
+        sb.append(certPath.toString());
+        sb.append("\n]"); //$NON-NLS-1$
+        return sb.toString();
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/cert/PKIXCertPathChecker.java b/libcore/security/src/main/java/java/security/cert/PKIXCertPathChecker.java
new file mode 100644
index 0000000..f448bee
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/PKIXCertPathChecker.java
@@ -0,0 +1,71 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public abstract class PKIXCertPathChecker implements Cloneable {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    protected PKIXCertPathChecker() {}
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new Error(e);
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract void init(boolean forward)
+        throws CertPathValidatorException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract boolean isForwardCheckingSupported();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract Set<String> getSupportedExtensions();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract void check(Certificate cert, Collection<String> unresolvedCritExts)
+        throws CertPathValidatorException;
+}
diff --git a/libcore/security/src/main/java/java/security/cert/PKIXCertPathValidatorResult.java b/libcore/security/src/main/java/java/security/cert/PKIXCertPathValidatorResult.java
new file mode 100644
index 0000000..bcda383
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/PKIXCertPathValidatorResult.java
@@ -0,0 +1,107 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.security.PublicKey;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class PKIXCertPathValidatorResult implements CertPathValidatorResult {
+    // A trust anchor used during validation of certification path
+    private final TrustAnchor trustAnchor;
+    // Valid policy tree resulting from PKIX
+    // certification path validation algorithm
+    private final PolicyNode policyTree;
+    // Public key of the subject (target) certificate
+    private final PublicKey subjectPublicKey;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public PKIXCertPathValidatorResult(TrustAnchor trustAnchor,
+            PolicyNode policyTree, PublicKey subjectPublicKey) {
+        this.trustAnchor = trustAnchor;
+        this.policyTree = policyTree;
+        this.subjectPublicKey = subjectPublicKey;
+        if (this.trustAnchor == null) {
+            throw new NullPointerException(Messages.getString("security.64")); //$NON-NLS-1$
+        }
+        if (this.subjectPublicKey == null) {
+            throw new NullPointerException(
+                    Messages.getString("security.65")); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public PolicyNode getPolicyTree() {
+        return policyTree;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public PublicKey getPublicKey() {
+        return subjectPublicKey;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public TrustAnchor getTrustAnchor() {
+        return trustAnchor;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            // Actually, the exception will not be thrown out.
+            throw new Error(e);
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer(super.toString());
+        sb.append(": [\n Trust Anchor: "); //$NON-NLS-1$
+        sb.append(trustAnchor.toString());
+        sb.append("\n Policy Tree: "); //$NON-NLS-1$
+        sb.append(policyTree == null ? "no valid policy tree\n" //$NON-NLS-1$
+                                     : policyTree.toString());
+        sb.append("\n Subject Public Key: "); //$NON-NLS-1$
+        sb.append(subjectPublicKey.toString());
+        sb.append("\n]"); //$NON-NLS-1$
+        return sb.toString();
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/cert/PKIXParameters.java b/libcore/security/src/main/java/java/security/cert/PKIXParameters.java
new file mode 100644
index 0000000..3246d89
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/PKIXParameters.java
@@ -0,0 +1,491 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class PKIXParameters implements CertPathParameters {
+    // Set of trust anchors - most trusted CAs
+    private Set<TrustAnchor> trustAnchors;
+    // Set of acceptable initial policy identifiers (OID strings)
+    private Set<String> initialPolicies;
+    // List of cert stores that used to find certificates and CRLs
+    private List<CertStore> certStores;
+    // Time for which the validity of the certification
+    // patch should be determined
+    private Date date;
+    // List of certification patch checkers (PKIXCertPathChecker)
+    private List<PKIXCertPathChecker> certPathCheckers;
+    // Preferred signature provider name
+    private String sigProvider;
+    // Required constraints on the target certificate
+    private CertSelector targetCertConstraints;
+    // Indicates whether cert revocation is enabled or not
+    private boolean revocationEnabled = true;
+    // Indicates whether explicit policy required or not
+    private boolean explicitPolicyRequired = false;
+    // Indicates whether policy mapping inhibited or not
+    private boolean policyMappingInhibited = false;
+    // Indicates whether any policy inhibited or not
+    private boolean anyPolicyInhibited = false;
+    // Indicates whether certificates that include policy
+    // qualifiers in a certificate policies extension that
+    // is marked critical must be rejected or not
+    private boolean policyQualifiersRejected = true;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public PKIXParameters(Set<TrustAnchor> trustAnchors)
+        throws InvalidAlgorithmParameterException {
+        if (trustAnchors == null) {
+            throw new NullPointerException(Messages.getString("security.6F")); //$NON-NLS-1$
+        }
+        checkTrustAnchors(trustAnchors);
+        this.trustAnchors = new HashSet<TrustAnchor>(trustAnchors);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public PKIXParameters(KeyStore keyStore)
+        throws KeyStoreException,
+               InvalidAlgorithmParameterException {
+        if (keyStore == null) {
+            throw new NullPointerException(Messages.getString("security.41")); //$NON-NLS-1$
+        }
+        // Will throw KeyStoreException if
+        // keyStore has not been initialized (loaded)
+        if (keyStore.size() == 0) {
+            throw new InvalidAlgorithmParameterException(
+                    Messages.getString("security.6A")); //$NON-NLS-1$
+        }
+        // keyStore is not null and loaded
+        trustAnchors = new HashSet<TrustAnchor>();
+        for (Enumeration i = keyStore.aliases(); i.hasMoreElements();) {
+            String alias = (String) i.nextElement();
+            if (keyStore.isCertificateEntry(alias)) {
+                // this is trusted certificate entry
+                // check if it is X509Cerificate
+                Certificate c = keyStore.getCertificate(alias);
+                // add only X509Cerificate
+                // ignore all other types
+                if (c instanceof X509Certificate) {
+                    trustAnchors.add(new TrustAnchor((X509Certificate)c, null));
+                }
+            }
+        }
+        checkTrustAnchors(trustAnchors);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Set<TrustAnchor> getTrustAnchors() {
+        return Collections.unmodifiableSet(trustAnchors);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setTrustAnchors(Set<TrustAnchor> trustAnchors)
+        throws InvalidAlgorithmParameterException {
+        if (trustAnchors == null) {
+            throw new NullPointerException(
+                    Messages.getString("security.6F")); //$NON-NLS-1$
+        }
+        checkTrustAnchors(trustAnchors);
+        // make shallow copy
+        this.trustAnchors = new HashSet<TrustAnchor>(trustAnchors);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public boolean isAnyPolicyInhibited() {
+        return anyPolicyInhibited;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setAnyPolicyInhibited(boolean anyPolicyInhibited) {
+        this.anyPolicyInhibited = anyPolicyInhibited;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public List<PKIXCertPathChecker> getCertPathCheckers() {
+        if (certPathCheckers == null) {
+            // set to empty List if has not been set yet
+            certPathCheckers = new ArrayList<PKIXCertPathChecker>();
+        }
+        if (certPathCheckers.isEmpty()) {
+            // no content - no need to copy,
+            // just return immutable view of the same
+            // empty List each time
+            return Collections.unmodifiableList(certPathCheckers);
+        }
+        // List is not empty - do deep copy
+        ArrayList<PKIXCertPathChecker> modifiableList = 
+            new ArrayList<PKIXCertPathChecker>();
+        for (Iterator<PKIXCertPathChecker> i 
+                = certPathCheckers.iterator(); i.hasNext();) {
+            modifiableList.add((PKIXCertPathChecker)i.next().clone());
+        }
+        return Collections.unmodifiableList(modifiableList);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setCertPathCheckers(List<PKIXCertPathChecker> certPathCheckers) {
+        if (certPathCheckers == null || certPathCheckers.isEmpty()) {
+            // empty list or null provided
+            if (this.certPathCheckers != null &&
+               !this.certPathCheckers.isEmpty()) {
+                // discard non-empty list
+                this.certPathCheckers = null;
+            }
+            return;
+        }
+        // non-empty list provided - do deep copy
+        this.certPathCheckers = new ArrayList<PKIXCertPathChecker>();
+        for (Iterator<PKIXCertPathChecker> i 
+                = certPathCheckers.iterator(); i.hasNext();) {
+            this.certPathCheckers.add((PKIXCertPathChecker)i.next().clone());
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void addCertPathChecker(PKIXCertPathChecker checker) {
+        if (checker == null) {
+            // do nothing if null provided
+            return;
+        }
+        if (certPathCheckers == null) {
+            // set to empty List if has not been set yet
+            certPathCheckers = new ArrayList<PKIXCertPathChecker>();
+        }
+        // add a copy to avoid possible modifications
+        certPathCheckers.add((PKIXCertPathChecker) checker.clone());
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public List<CertStore> getCertStores() {
+        if (certStores == null) {
+            // set to empty List if has not been set yet
+            certStores = new ArrayList<CertStore>();
+        }
+        if (certStores.isEmpty()) {
+            // no content - no need to copy,
+            // just return immutable view of the same
+            // empty List each time
+            return Collections.unmodifiableList(certStores);
+        }
+        // List is not empty - do shallow copy
+        ArrayList<CertStore> modifiableList 
+            = new ArrayList<CertStore>(certStores);
+        return Collections.unmodifiableList(modifiableList);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setCertStores(List<CertStore> certStores) {
+        if (certStores == null || certStores.isEmpty()) {
+            // empty list or null provided
+            if (this.certStores != null && !this.certStores.isEmpty()) {
+                // discard non-empty list
+                this.certStores = null;
+            }
+            return;
+        }
+        // non-empty list provided - do shallow copy
+        this.certStores = new ArrayList(certStores);
+        // check that all elements are CertStore
+        for (Iterator i = this.certStores.iterator(); i.hasNext();) {
+            if (!(i.next() instanceof CertStore)) {
+                throw new ClassCastException(Messages.getString("security.6B")); //$NON-NLS-1$
+            }
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void addCertStore(CertStore store) {
+        if (store == null) {
+            // do nothing if null provided
+            return;
+        }
+        if (certStores == null) {
+            // set to empty List if has not been set yet
+            certStores = new ArrayList();
+        }
+        // add store
+        certStores.add(store);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Date getDate() {
+        return date == null ? null : (Date)date.clone();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setDate(Date date) {
+        this.date = (date == null ? null : new Date(date.getTime()));
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public boolean isExplicitPolicyRequired() {
+        return explicitPolicyRequired;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setExplicitPolicyRequired(boolean explicitPolicyRequired) {
+        this.explicitPolicyRequired = explicitPolicyRequired;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Set<String> getInitialPolicies() {
+        if (initialPolicies == null) {
+            // set to empty Set if has not been set yet
+            initialPolicies = new HashSet();
+        }
+        if (initialPolicies.isEmpty()) {
+            // no content - no need to copy,
+            // just return immutable view of the same
+            // empty Set each time
+            return Collections.unmodifiableSet(initialPolicies);
+        }
+        // List is not empty - do shallow copy
+        HashSet modifiableSet = new HashSet(initialPolicies);
+        return Collections.unmodifiableSet(modifiableSet);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setInitialPolicies(Set<String> initialPolicies) {
+        if (initialPolicies == null || initialPolicies.isEmpty()) {
+            // empty list or null provided
+            if (this.initialPolicies != null &&
+               !this.initialPolicies.isEmpty()) {
+                // discard non-empty list
+                this.initialPolicies = null;
+            }
+            return;
+        }
+        // non-empty list provided - do shallow copy
+        this.initialPolicies = new HashSet(initialPolicies);
+        // check that all elements are String
+        for (Iterator i = this.initialPolicies.iterator(); i.hasNext();) {
+            if (!(i.next() instanceof String)) {
+                throw new ClassCastException(Messages.getString("security.6C")); //$NON-NLS-1$
+            }
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public boolean isPolicyMappingInhibited() {
+        return policyMappingInhibited;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setPolicyMappingInhibited(boolean policyMappingInhibited) {
+        this.policyMappingInhibited = policyMappingInhibited;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public boolean getPolicyQualifiersRejected() {
+        return policyQualifiersRejected;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setPolicyQualifiersRejected(boolean policyQualifiersRejected) {
+        this.policyQualifiersRejected = policyQualifiersRejected;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public boolean isRevocationEnabled() {
+        return revocationEnabled;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setRevocationEnabled(boolean revocationEnabled) {
+        this.revocationEnabled = revocationEnabled;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public String getSigProvider() {
+        return sigProvider;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setSigProvider(String sigProvider) {
+        this.sigProvider = sigProvider;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public CertSelector getTargetCertConstraints() {
+        return (targetCertConstraints == null ? null
+                :(CertSelector)targetCertConstraints.clone());
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setTargetCertConstraints(CertSelector targetCertConstraints) {
+        this.targetCertConstraints = (targetCertConstraints == null ? null
+                : (CertSelector)targetCertConstraints.clone());
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Object clone() {
+        try {
+            // do shallow copy first
+            PKIXParameters ret = (PKIXParameters)super.clone();
+            // copy fields containing references to mutable objects
+            if (this.certStores != null) {
+                ret.certStores = new ArrayList(this.certStores);
+            }
+            if (this.certPathCheckers != null) {
+                ret.certPathCheckers = new ArrayList(this.certPathCheckers);
+            }
+            return ret;
+        } catch (CloneNotSupportedException e) {
+            throw new Error(e);
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public String toString() {
+        StringBuffer sb =
+            new StringBuffer("[\n Trust Anchors: "); //$NON-NLS-1$
+        sb.append(trustAnchors);
+        sb.append("\n Revocation Enabled: "); //$NON-NLS-1$
+        sb.append(revocationEnabled);
+        sb.append("\n Explicit Policy Required: "); //$NON-NLS-1$
+        sb.append(explicitPolicyRequired);
+        sb.append("\n Policy Mapping Inhibited: "); //$NON-NLS-1$
+        sb.append(policyMappingInhibited);
+        sb.append("\n Any Policy Inhibited: "); //$NON-NLS-1$
+        sb.append(anyPolicyInhibited);
+        sb.append("\n Policy Qualifiers Rejected: "); //$NON-NLS-1$
+        sb.append(policyQualifiersRejected);
+        sb.append("\n Initial Policy OIDs: "); //$NON-NLS-1$
+        sb.append((initialPolicies == null || initialPolicies.isEmpty())
+                ? "any" : initialPolicies.toString()); //$NON-NLS-1$
+        sb.append("\n Cert Stores: "); //$NON-NLS-1$
+        sb.append((certStores==null||certStores.isEmpty())?
+                "no":certStores.toString()); //$NON-NLS-1$
+        sb.append("\n Validity Date: "); //$NON-NLS-1$
+        sb.append(date);
+        sb.append("\n Cert Path Checkers: "); //$NON-NLS-1$
+        sb.append((certPathCheckers==null||certPathCheckers.isEmpty())?
+                "no":certPathCheckers.toString()); //$NON-NLS-1$
+        sb.append("\n Signature Provider: "); //$NON-NLS-1$
+        sb.append(sigProvider);
+        sb.append("\n Target Certificate Constraints: "); //$NON-NLS-1$
+        sb.append(targetCertConstraints);
+        sb.append("\n]"); //$NON-NLS-1$
+        return sb.toString();
+    }
+
+    //
+    // Private stuff
+    //
+
+    //
+    // Checks that 'trustAnchors' contains
+    // only TrustAnchor instances.
+    // Throws InvalidAlgorithmParameterException if trustAnchors set is empty.
+    //
+    private void checkTrustAnchors(Set trustAnchors)
+        throws InvalidAlgorithmParameterException {
+        if (trustAnchors.isEmpty()) {
+            throw new InvalidAlgorithmParameterException(
+                    Messages.getString("security.6D")); //$NON-NLS-1$
+        }
+        for (Iterator i = trustAnchors.iterator(); i.hasNext();) {
+            if (!(i.next() instanceof TrustAnchor)) {
+                throw new ClassCastException(
+             Messages.getString("security.6E")); //$NON-NLS-1$
+            }
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/cert/PolicyNode.java b/libcore/security/src/main/java/java/security/cert/PolicyNode.java
new file mode 100644
index 0000000..24ddd5b
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/PolicyNode.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface PolicyNode {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Iterator<? extends PolicyNode> getChildren();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public int getDepth();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Set<String> getExpectedPolicies();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public PolicyNode getParent();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Set<? extends PolicyQualifierInfo> getPolicyQualifiers();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public String getValidPolicy();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public boolean isCritical();
+}
diff --git a/libcore/security/src/main/java/java/security/cert/PolicyQualifierInfo.java b/libcore/security/src/main/java/java/security/cert/PolicyQualifierInfo.java
new file mode 100644
index 0000000..acad3bc
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/PolicyQualifierInfo.java
@@ -0,0 +1,106 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.io.IOException;
+
+import org.apache.harmony.security.asn1.ObjectIdentifier;
+import org.apache.harmony.security.internal.nls.Messages;
+import org.apache.harmony.security.utils.Array;
+
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class PolicyQualifierInfo {
+    // This PolicyQualifierInfo DER encoding
+    private final byte[] encoded;
+    // This PolicyQualifierInfo policy qualifier id -
+    // OID represented as String containing non-negative integers
+    // separated by periods
+    private final String policyQualifierId;
+    // DER encoding of the policy qualifier - part of encoded
+    private final byte[] policyQualifier;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public PolicyQualifierInfo(byte[] encoded) throws IOException {
+        if (encoded == null) {
+            throw new NullPointerException(Messages.getString("security.0A")); //$NON-NLS-1$
+        }
+        if (encoded.length == 0) {
+            throw new IOException(Messages.getString("security.69")); //$NON-NLS-1$
+        }
+        this.encoded = new byte[encoded.length];
+        System.arraycopy(encoded, 0, this.encoded, 0, this.encoded.length);
+        
+        // DER Decoding:
+        Object[] decoded = (Object[]) org.apache.harmony.security.x509.PolicyQualifierInfo.ASN1
+                .decode(this.encoded);
+        policyQualifierId = ObjectIdentifier.toString((int[]) decoded[0]);
+        policyQualifier = (byte[]) decoded[1];
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public final byte[] getEncoded() {
+        byte[] ret = new byte[encoded.length];
+        System.arraycopy(encoded, 0, ret, 0, encoded.length);
+        return ret;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public final String getPolicyQualifierId() {
+        return policyQualifierId;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public final byte[] getPolicyQualifier() {
+        if (policyQualifier == null) {
+            return null;
+        }
+        byte[] ret = new byte[policyQualifier.length];
+        System.arraycopy(policyQualifier, 0, ret, 0, policyQualifier.length);
+        return ret;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public String toString() {
+        StringBuffer sb =
+            new StringBuffer("PolicyQualifierInfo: [\npolicyQualifierId: "); //$NON-NLS-1$
+        sb.append(policyQualifierId);
+        sb.append("\npolicyQualifier: \n"); //$NON-NLS-1$
+        sb.append(Array.toString(policyQualifier, " ")); //$NON-NLS-1$
+        sb.append("]"); //$NON-NLS-1$
+        return sb.toString();
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/cert/TrustAnchor.java b/libcore/security/src/main/java/java/security/cert/TrustAnchor.java
new file mode 100644
index 0000000..6d0cc3b
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/TrustAnchor.java
@@ -0,0 +1,219 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.io.IOException;
+import java.security.PublicKey;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.internal.nls.Messages;
+import org.apache.harmony.security.utils.Array;
+import org.apache.harmony.security.x509.NameConstraints;
+
+
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class TrustAnchor {
+    // Most trusted CA as a X500Principal
+    private final X500Principal caPrincipal;
+    // Most trusted CA name
+    private final String caName;
+    // Most trusted CA public key
+    private final PublicKey caPublicKey;
+    // Most trusted CA certificate
+    private final X509Certificate trustedCert;
+    // Name constraints extension
+    private final byte[] nameConstraints;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public TrustAnchor(X509Certificate trustedCert, byte[] nameConstraints) {
+        if (trustedCert == null) {
+            throw new NullPointerException(Messages.getString("security.5C")); //$NON-NLS-1$
+        }
+        this.trustedCert = trustedCert;
+        // copy nameConstraints if not null
+        if (nameConstraints != null) {
+            this.nameConstraints = new byte[nameConstraints.length];
+            System.arraycopy(nameConstraints, 0,
+                    this.nameConstraints, 0, this.nameConstraints.length);
+            processNameConstraints();
+        } else {
+            this.nameConstraints = null;
+        }
+        this.caName = null;
+        this.caPrincipal = null;
+        this.caPublicKey = null;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public TrustAnchor(String caName, PublicKey caPublicKey,
+            byte[] nameConstraints) {
+        if (caName == null) {
+            throw new NullPointerException(Messages.getString("security.5D")); //$NON-NLS-1$
+        }
+        this.caName = caName;
+        if (caPublicKey == null) {
+            throw new NullPointerException(Messages.getString("security.5E")); //$NON-NLS-1$
+        }
+        this.caPublicKey = caPublicKey;
+        // copy nameConstraints if not null
+        if (nameConstraints != null) {
+            this.nameConstraints = new byte[nameConstraints.length];
+            System.arraycopy(nameConstraints, 0,
+                    this.nameConstraints, 0, this.nameConstraints.length);
+            processNameConstraints();
+        } else {
+            this.nameConstraints = null;
+        }
+
+        this.trustedCert = null;
+
+        // X500Principal checks caName validity
+        if (caName.length() == 0) {
+            throw new IllegalArgumentException(
+                    Messages.getString("security.5F")); //$NON-NLS-1$
+        }
+        this.caPrincipal = new X500Principal(this.caName);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public TrustAnchor(X500Principal caPrincipal,
+            PublicKey caPublicKey, byte[] nameConstraints) {
+        if (caPrincipal == null) {
+            throw new NullPointerException(Messages.getString("security.60")); //$NON-NLS-1$
+        }
+        this.caPrincipal = caPrincipal;
+        if (caPublicKey == null) {
+            throw new NullPointerException(Messages.getString("security.5E")); //$NON-NLS-1$
+        }
+        this.caPublicKey = caPublicKey;
+        // copy nameConstraints if not null
+        if (nameConstraints != null) {
+            this.nameConstraints = new byte[nameConstraints.length];
+            System.arraycopy(nameConstraints, 0,
+                    this.nameConstraints, 0, this.nameConstraints.length);
+            processNameConstraints();
+        } else {
+            this.nameConstraints = null;
+        }
+
+        this.trustedCert = null;
+        this.caName = caPrincipal.getName();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public final byte[] getNameConstraints() {
+        if (nameConstraints == null) {
+            return null;
+        }
+        byte[] ret = new byte[nameConstraints.length];
+            System.arraycopy(nameConstraints, 0,
+                    ret, 0, nameConstraints.length);
+        return ret;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public final X509Certificate getTrustedCert() {
+        return trustedCert;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public final X500Principal getCA() {
+        return caPrincipal;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public final String getCAName() {
+        return caName;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public final PublicKey getCAPublicKey() {
+        return caPublicKey;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer("TrustAnchor: [\n"); //$NON-NLS-1$
+        if (trustedCert != null) {
+            sb.append("Trusted CA certificate: "); //$NON-NLS-1$
+            sb.append(trustedCert);
+            sb.append("\n"); //$NON-NLS-1$
+        }
+        if (caPrincipal != null) {
+            sb.append("Trusted CA Name: "); //$NON-NLS-1$
+            sb.append(caPrincipal);
+            sb.append("\n"); //$NON-NLS-1$
+        }
+        if (caPublicKey != null) {
+            sb.append("Trusted CA Public Key: "); //$NON-NLS-1$
+            sb.append(caPublicKey);
+            sb.append("\n"); //$NON-NLS-1$
+        }
+        // FIXME if needed:
+        if (nameConstraints != null) {
+            sb.append("Name Constraints:\n"); //$NON-NLS-1$
+            sb.append(Array.toString(nameConstraints, "    ")); //$NON-NLS-1$
+        }
+        sb.append("\n]"); //$NON-NLS-1$
+        return sb.toString();
+    }
+
+    //
+    // Private stuff
+    //
+
+    // Decodes and checks NameConstraints structure.
+    // Throws IllegalArgumentException if NameConstraints
+    // encoding is invalid.
+    private void processNameConstraints() {
+        try {
+            // decode and check nameConstraints
+            NameConstraints.ASN1.decode(nameConstraints);
+        } catch (IOException e) {
+            throw new IllegalArgumentException(e.getMessage());
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/cert/X509CRL.java b/libcore/security/src/main/java/java/security/cert/X509CRL.java
new file mode 100644
index 0000000..e502f2f
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/X509CRL.java
@@ -0,0 +1,197 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.io.ByteArrayInputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Extension;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Set;
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref
+ */
+public abstract class X509CRL extends CRL implements X509Extension {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    protected X509CRL() {
+        super("X.509"); //$NON-NLS-1$
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public boolean equals(Object other) {
+        if (other == this) {
+            return true;
+        }
+        if (!(other instanceof X509CRL)) {
+            return false;
+        }
+        X509CRL obj = (X509CRL) other;
+        try {
+            return Arrays.equals(getEncoded(), obj.getEncoded());
+        } catch (CRLException e) {
+            return false;
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public int hashCode() {
+        try {
+            int res = 0;
+            byte[] array = getEncoded();
+            for (int i=0; i<array.length; i++) {
+                res += array[i] & 0xFF;
+            }
+            return res;
+        } catch (CRLException e) {
+            return 0;
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract byte[] getEncoded() throws CRLException;
+
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract void verify(PublicKey key)
+                     throws CRLException, NoSuchAlgorithmException,
+                            InvalidKeyException, NoSuchProviderException,
+                            SignatureException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract void verify(PublicKey key, String sigProvider)
+                     throws CRLException, NoSuchAlgorithmException,
+                            InvalidKeyException, NoSuchProviderException,
+                            SignatureException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract int getVersion();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract Principal getIssuerDN();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public X500Principal getIssuerX500Principal() {
+        try {
+            // TODO if there is no X.509 certificate provider installed
+            // should we try to access Harmony X509CRLImpl via classForName?
+            CertificateFactory factory = CertificateFactory
+                    .getInstance("X.509"); //$NON-NLS-1$
+
+            X509CRL crl = (X509CRL) factory
+                    .generateCRL(new ByteArrayInputStream(getEncoded()));
+
+            return crl.getIssuerX500Principal();
+
+        } catch (Exception e) {
+            throw new RuntimeException(Messages.getString("security.59"), e); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract Date getThisUpdate();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract Date getNextUpdate();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract X509CRLEntry getRevokedCertificate(BigInteger serialNumber);
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public X509CRLEntry getRevokedCertificate(X509Certificate certificate) {
+        if (certificate == null) {
+            throw new NullPointerException();
+        }
+        return getRevokedCertificate(certificate.getSerialNumber());
+    }
+        
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract Set<? extends X509CRLEntry> getRevokedCertificates();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract byte[] getTBSCertList() throws CRLException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract byte[] getSignature();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract String getSigAlgName();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract String getSigAlgOID();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract byte[] getSigAlgParams();
+}
+
diff --git a/libcore/security/src/main/java/java/security/cert/X509CRLEntry.java b/libcore/security/src/main/java/java/security/cert/X509CRLEntry.java
new file mode 100644
index 0000000..d726f9d
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/X509CRLEntry.java
@@ -0,0 +1,105 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.math.BigInteger;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Extension;
+import java.util.Arrays;
+import java.util.Date;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * @com.intel.drl.spec_ref
+ */
+public abstract class X509CRLEntry implements X509Extension {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public X509CRLEntry() {}
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public boolean equals(Object other) {
+        if (other == this) {
+            return true;
+        }
+        if (!(other instanceof X509CRLEntry)) {
+            return false;
+        }
+        X509CRLEntry obj = (X509CRLEntry) other;
+        try {
+            return Arrays.equals(getEncoded(), obj.getEncoded());
+        } catch (CRLException e) {
+            return false;
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public int hashCode() {
+        int res = 0;
+        try {
+            byte[] array = getEncoded();
+            for (int i=0; i<array.length; i++) {
+                res += array[i] & 0xFF;
+            }
+        } catch (CRLException e) {
+        }
+        return res;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract byte[] getEncoded() throws CRLException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract BigInteger getSerialNumber();
+
+    public X500Principal getCertificateIssuer() {
+        return null;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract Date getRevocationDate();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract boolean hasExtensions();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract String toString();
+}
+
diff --git a/libcore/security/src/main/java/java/security/cert/X509CRLSelector.java b/libcore/security/src/main/java/java/security/cert/X509CRLSelector.java
new file mode 100644
index 0000000..d679e99
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/X509CRLSelector.java
@@ -0,0 +1,351 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Alexander Y. Kleymenov
+ * @version $Revision$
+ */
+
+package java.security.cert;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.asn1.ASN1Integer;
+import org.apache.harmony.security.asn1.ASN1OctetString;
+import org.apache.harmony.security.internal.nls.Messages;
+import org.apache.harmony.security.x501.Name;
+
+/**
+ * @com.intel.drl.spec_ref
+ */
+public class X509CRLSelector implements CRLSelector {
+
+    // issuerNames criterion:
+    // contains X.500 distinguished names in CANONICAL format
+    private ArrayList<String> issuerNames;
+    // contains X500Principal objects corresponding to the names
+    // from issuerNames collection (above)
+    private ArrayList<X500Principal> issuerPrincipals;
+    // minCRLNumber criterion
+    private BigInteger minCRL;
+    // maxCRLNumber criterion
+    private BigInteger maxCRL;
+    // dateAndTime criterion
+    private long dateAndTime = -1;
+    // the certificate being checked
+    private X509Certificate certificateChecking;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public X509CRLSelector() { }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setIssuers(Collection<X500Principal> issuers) {
+        if (issuers == null) {
+            issuerNames = null;
+            issuerPrincipals = null;
+            return;
+        }
+        issuerNames = new ArrayList<String>(issuers.size());
+        issuerPrincipals = new ArrayList<X500Principal>(issuers);
+        for (X500Principal issuer: issuers) {
+            issuerNames.add(issuer.getName(X500Principal.CANONICAL));
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setIssuerNames(Collection<?> names) throws IOException {
+        if (names == null) {
+            issuerNames = null;
+            issuerPrincipals = null;
+            return;
+        }
+        if (names.size() == 0) {
+            return;
+        }
+        issuerNames = new ArrayList<String>(names.size());
+        for (Object name: names) {
+            if (name instanceof String) {
+                issuerNames.add(
+                        new Name((String) name).getName(
+                            X500Principal.CANONICAL));
+            } else if (name instanceof byte[]) {
+                issuerNames.add(
+                        new Name((byte[]) name).getName(
+                            X500Principal.CANONICAL));
+            } else {
+                throw new IOException(
+                        Messages.getString("security.62")); //$NON-NLS-1$
+            }
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void addIssuer(X500Principal issuer) {
+        if (issuer == null) {
+            throw new NullPointerException(Messages.getString("security.61")); //$NON-NLS-1$
+        }
+        if (issuerNames == null) {
+            issuerNames = new ArrayList<String>();
+        }
+        String name = issuer.getName(X500Principal.CANONICAL);
+        if (!issuerNames.contains(name)) {
+            issuerNames.add(name);
+        }
+        if (issuerPrincipals == null) {
+            issuerPrincipals = new ArrayList<X500Principal>(issuerNames.size());
+        }
+        // extend the list of issuer Principals
+        int size = issuerNames.size() - 1;
+        for (int i=issuerPrincipals.size(); i<size; i++) {
+            issuerPrincipals.add(new X500Principal(issuerNames.get(i)));
+        }
+        issuerPrincipals.add(issuer);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void addIssuerName(String iss_name) throws IOException {
+        if (issuerNames == null) {
+            issuerNames = new ArrayList<String>();
+        }
+
+        if (iss_name == null) {
+            iss_name = ""; //$NON-NLS-1$
+        }
+
+        String name = new Name(iss_name).getName(X500Principal.CANONICAL);
+        if (!issuerNames.contains(name)) {
+            issuerNames.add(name);
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void addIssuerName(byte[] iss_name) throws IOException {
+        if (iss_name == null) {
+            throw new NullPointerException(Messages.getString("security.63")); //$NON-NLS-1$
+        }
+        if (issuerNames == null) {
+            issuerNames = new ArrayList<String>();
+        }
+        String name = new Name(iss_name).getName(X500Principal.CANONICAL);
+        if (!issuerNames.contains(name)) {
+            issuerNames.add(name);
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setMinCRLNumber(BigInteger minCRL) {
+        this.minCRL = minCRL;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setMaxCRLNumber(BigInteger maxCRL) {
+        this.maxCRL = maxCRL;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setDateAndTime(Date dateAndTime) {
+        if (dateAndTime == null) {
+            this.dateAndTime = -1;
+            return;
+        }
+        this.dateAndTime = dateAndTime.getTime();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setCertificateChecking(X509Certificate cert) {
+        this.certificateChecking = cert;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Collection<X500Principal> getIssuers() {
+        if (issuerNames == null) {
+            return null;
+        }
+        if (issuerPrincipals == null) {
+            issuerPrincipals = new ArrayList<X500Principal>(issuerNames.size());
+        }
+        int size = issuerNames.size();
+        // extend the list of issuer Principals
+        for (int i=issuerPrincipals.size(); i<size; i++) {
+            issuerPrincipals.add(new X500Principal(issuerNames.get(i)));
+        }
+        return Collections.unmodifiableCollection(issuerPrincipals);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Collection<Object> getIssuerNames() {
+        if (issuerNames == null) {
+            return null;
+        }
+        return Collections.unmodifiableCollection((ArrayList<?>) issuerNames);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getMinCRL() {
+        return minCRL;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getMaxCRL() {
+        return maxCRL;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Date getDateAndTime() {
+        if (dateAndTime == -1) {
+            return null;
+        }
+        return new Date(dateAndTime);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public X509Certificate getCertificateChecking() {
+        return certificateChecking;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public String toString() {
+        StringBuffer result = new StringBuffer();
+        result.append("X509CRLSelector:\n["); //$NON-NLS-1$
+        if (issuerNames != null) {
+            result.append("\n  IssuerNames:\n  ["); //$NON-NLS-1$
+            int size = issuerNames.size();
+            for (int i=0; i<size; i++) {
+                result.append("\n    " //$NON-NLS-1$
+                    + issuerNames.get(i));
+            }
+            result.append("\n  ]"); //$NON-NLS-1$
+        }
+        if (minCRL != null) {
+            result.append("\n  minCRL: " + minCRL); //$NON-NLS-1$
+        }
+        if (maxCRL != null) {
+            result.append("\n  maxCRL: " + maxCRL); //$NON-NLS-1$
+        }
+        if (dateAndTime != -1) {
+            result.append("\n  dateAndTime: " + (new Date(dateAndTime))); //$NON-NLS-1$
+        }
+        if (certificateChecking != null) {
+            result.append("\n  certificateChecking: " + certificateChecking); //$NON-NLS-1$
+        }
+        result.append("\n]"); //$NON-NLS-1$
+        return result.toString();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public boolean match(CRL crl) {
+        if (!(crl instanceof X509CRL)) {
+            return false;
+        }
+        X509CRL crlist = (X509CRL) crl;
+        if ((issuerNames != null) &&
+                // the search speed depends on the class of issuerNames
+                !(issuerNames.contains(
+                        crlist.getIssuerX500Principal().getName(
+                            X500Principal.CANONICAL)))) {
+            return false;
+        }
+        if ((minCRL != null) || (maxCRL != null)) {
+            try {
+                // As specified in rfc 3280 (http://www.ietf.org/rfc/rfc3280.txt)
+                // CRL Number Extension's OID is 2.5.29.20 .
+                byte[] bytes = crlist.getExtensionValue("2.5.29.20"); //$NON-NLS-1$
+                bytes = (byte[]) ASN1OctetString.getInstance().decode(bytes);
+                BigInteger crlNumber = new BigInteger((byte[])
+                        ASN1Integer.getInstance().decode(bytes));
+                if ((minCRL != null) && (crlNumber.compareTo(minCRL) < 0)) {
+                    return false;
+                }
+                if ((maxCRL != null) && (crlNumber.compareTo(maxCRL) > 0)) {
+                    return false;
+                }
+            } catch (IOException e) {
+                return false;
+            }
+        }
+        if (dateAndTime != -1) {
+            Date thisUp = crlist.getThisUpdate();
+            Date nextUp = crlist.getNextUpdate();
+            if ((thisUp == null) || (nextUp == null)) {
+                return false;
+            }
+            if ((dateAndTime < thisUp.getTime())
+                                || (dateAndTime > nextUp.getTime())) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Object clone() {
+        X509CRLSelector result = new X509CRLSelector();
+        if (issuerNames != null) {
+            result.issuerNames = new ArrayList<String>(issuerNames);
+        }
+        result.minCRL = minCRL;
+        result.maxCRL = maxCRL;
+        result.dateAndTime = dateAndTime;
+        result.certificateChecking = certificateChecking;
+        return result;
+    }
+}
+
diff --git a/libcore/security/src/main/java/java/security/cert/X509CertSelector.java b/libcore/security/src/main/java/java/security/cert/X509CertSelector.java
new file mode 100644
index 0000000..be2567e
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/X509CertSelector.java
@@ -0,0 +1,1113 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Alexander Y. Kleymenov
+ * @version $Revision$
+ */
+
+package java.security.cert;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.PublicKey;
+import java.security.cert.CertSelector;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.asn1.ASN1OctetString;
+import org.apache.harmony.security.internal.nls.Messages;
+import org.apache.harmony.security.x509.AlgorithmIdentifier;
+import org.apache.harmony.security.x509.CertificatePolicies;
+import org.apache.harmony.security.x509.GeneralName;
+import org.apache.harmony.security.x509.GeneralNames;
+import org.apache.harmony.security.x509.NameConstraints;
+import org.apache.harmony.security.x509.PolicyInformation;
+import org.apache.harmony.security.x509.PrivateKeyUsagePeriod;
+import org.apache.harmony.security.x509.SubjectPublicKeyInfo;
+
+
+
+/**
+ * @com.intel.drl.spec_ref
+ */
+public class X509CertSelector implements CertSelector {
+
+    // match criteria
+    private X509Certificate certificateEquals;
+    private BigInteger serialNumber;
+    private X500Principal issuer;
+    private X500Principal subject;
+    private byte[] subjectKeyIdentifier;
+    private byte[] authorityKeyIdentifier;
+    private Date certificateValid;
+    private String subjectPublicKeyAlgID;
+    private Date privateKeyValid;
+    private byte[] subjectPublicKey;
+    private boolean[] keyUsage;
+    private Set extendedKeyUsage;
+    private boolean matchAllNames = true;
+    private int pathLen = -1;
+    private List[] subjectAltNames;
+    private NameConstraints nameConstraints;
+    private Set policies;
+    private ArrayList pathToNames;
+
+    // needed to avoid needless encoding/decoding work
+    private PublicKey subjectPublicKeyImpl;
+    private String issuerName;
+    private byte[] issuerBytes;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public X509CertSelector() {}
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setCertificate(X509Certificate certificate) {
+        certificateEquals = certificate;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public X509Certificate getCertificate() {
+        return certificateEquals;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setSerialNumber(BigInteger serialNumber) {
+        this.serialNumber = serialNumber;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getSerialNumber() {
+        return serialNumber;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setIssuer(X500Principal issuer) {
+        this.issuer = issuer;
+        this.issuerName = null;
+        this.issuerBytes = null;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public X500Principal getIssuer() {
+        return issuer;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setIssuer(String issuerName) throws IOException {
+        if (issuerName == null) {
+            this.issuer = null;
+            this.issuerName = null;
+            this.issuerBytes = null;
+            return;
+        }
+        try {
+            this.issuer = new X500Principal(issuerName);
+            this.issuerName = issuerName;
+            this.issuerBytes = null;
+        } catch (IllegalArgumentException e) {
+            throw new IOException(e.getMessage());
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public String getIssuerAsString() {
+        if (issuer == null) {
+            return null;
+        }
+        if (issuerName == null) {
+            issuerName = issuer.getName();
+        }
+        return issuerName;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setIssuer(byte[] issuerDN) throws IOException {
+        if (issuerDN == null) {
+            issuer = null;
+            return;
+        }
+        try {
+            issuer = new X500Principal(issuerDN);
+            this.issuerName = null;
+            this.issuerBytes = new byte[issuerDN.length];
+            System.arraycopy(issuerDN, 0, this.issuerBytes, 0, issuerDN.length);
+        } catch (IllegalArgumentException e) {
+            throw new IOException(e.getMessage());
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public byte[] getIssuerAsBytes() throws IOException {
+        if (issuer == null) {
+            return null;
+        }
+        if (issuerBytes == null) {
+            issuerBytes = issuer.getEncoded();
+        }
+        byte[] result = new byte[issuerBytes.length];
+        System.arraycopy(issuerBytes, 0, result, 0, issuerBytes.length);
+        return result;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setSubject(X500Principal subject) {
+        this.subject = subject;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public X500Principal getSubject() {
+        return subject;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setSubject(String subjectDN) throws IOException {
+        if (subjectDN == null) {
+            subject = null;
+            return;
+        }
+        try {
+            subject = new X500Principal(subjectDN);
+        } catch (IllegalArgumentException e) {
+            throw new IOException(e.getMessage());
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public String getSubjectAsString() {
+        if (subject == null) {
+            return null;
+        }
+        return subject.getName();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setSubject(byte[] subjectDN) throws IOException {
+        if (subjectDN == null) {
+            subject = null;
+            return;
+        }
+        try {
+            subject = new X500Principal(subjectDN);
+        } catch (IllegalArgumentException e) {
+            throw new IOException(e.getMessage());
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public byte[] getSubjectAsBytes() throws IOException {
+        if (subject == null) {
+            return null;
+        }
+        return subject.getEncoded();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setSubjectKeyIdentifier(byte[] subjectKeyIdentifier) {
+        if (subjectKeyIdentifier == null) {
+            this.subjectKeyIdentifier = null;
+            return;
+        }
+        this.subjectKeyIdentifier = new byte[subjectKeyIdentifier.length];
+        System.arraycopy(subjectKeyIdentifier, 0, this.subjectKeyIdentifier, 0,
+                         subjectKeyIdentifier.length);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public byte[] getSubjectKeyIdentifier() {
+        if (subjectKeyIdentifier == null) {
+            return null;
+        }
+        byte[] res = new byte[subjectKeyIdentifier.length];
+        System.arraycopy(subjectKeyIdentifier, 0, res, 0, res.length);
+        return res;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setAuthorityKeyIdentifier(byte[] authorityKeyIdentifier) {
+        if (authorityKeyIdentifier == null) {
+            this.authorityKeyIdentifier = null;
+            return;
+        }
+        this.authorityKeyIdentifier = new byte[authorityKeyIdentifier.length];
+        System.arraycopy(authorityKeyIdentifier, 0,
+                         this.authorityKeyIdentifier, 0,
+                         authorityKeyIdentifier.length);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public byte[] getAuthorityKeyIdentifier() {
+        if (authorityKeyIdentifier == null) {
+            return null;
+        }
+        byte[] res = new byte[authorityKeyIdentifier.length];
+        System.arraycopy(authorityKeyIdentifier, 0, res, 0, res.length);
+        return res;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setCertificateValid(Date certificateValid) {
+        this.certificateValid = (certificateValid == null)
+                                ? null
+                                : (Date) certificateValid.clone();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Date getCertificateValid() {
+        return (certificateValid == null)
+                                ? null
+                                : (Date) certificateValid.clone();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setPrivateKeyValid(Date privateKeyValid) {
+        if (privateKeyValid == null) {
+            this.privateKeyValid = null;
+            return;
+        }
+        this.privateKeyValid = (Date) privateKeyValid.clone();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Date getPrivateKeyValid() {
+        if (privateKeyValid != null) {
+            return (Date) privateKeyValid.clone();
+        }
+        return null;
+    }
+
+    private void checkOID(String oid) throws IOException {
+        int beg = 0;
+        int end = oid.indexOf('.', beg);
+        try {
+            int comp = Integer.parseInt(oid.substring(beg, end));
+            beg = end + 1;
+            if ((comp < 0) || (comp > 2)) {
+                throw new IOException(Messages.getString("security.56", oid)); //$NON-NLS-1$
+            }
+            end = oid.indexOf('.', beg);
+            comp = Integer.parseInt(oid.substring(beg, end));
+            if ((comp < 0) || (comp > 39)) {
+                throw new IOException(Messages.getString("security.56", oid)); //$NON-NLS-1$
+            }
+        } catch (IndexOutOfBoundsException e) {
+            throw new IOException(Messages.getString("security.56", oid)); //$NON-NLS-1$
+        } catch (NumberFormatException e) {
+            throw new IOException(Messages.getString("security.56", oid)); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setSubjectPublicKeyAlgID(String oid) throws IOException {
+        if (oid == null) {
+            subjectPublicKeyAlgID = null;
+            return;
+        }
+        checkOID(oid);
+        subjectPublicKeyAlgID = oid;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public String getSubjectPublicKeyAlgID() {
+        return subjectPublicKeyAlgID;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setSubjectPublicKey(PublicKey key) {
+        subjectPublicKey = (key == null) ? null : key.getEncoded();
+        subjectPublicKeyImpl = key;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setSubjectPublicKey(byte[] key) throws IOException {
+        if (key == null) {
+            subjectPublicKey = null;
+            subjectPublicKeyImpl = null;
+            return;
+        }
+        subjectPublicKey = new byte[key.length];
+        System.arraycopy(key, 0, subjectPublicKey, 0, key.length);
+        subjectPublicKeyImpl = 
+            ((SubjectPublicKeyInfo) SubjectPublicKeyInfo.ASN1.decode(key))
+            .getPublicKey();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public PublicKey getSubjectPublicKey() {
+        return subjectPublicKeyImpl;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setKeyUsage(boolean[] keyUsage) {
+        if (keyUsage == null) {
+            this.keyUsage = null;
+            return;
+        }
+        this.keyUsage = new boolean[keyUsage.length];
+        System.arraycopy(keyUsage, 0, this.keyUsage, 0, keyUsage.length);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public boolean[] getKeyUsage() {
+        if (keyUsage == null) {
+            return null;
+        }
+        boolean[] result = new boolean[keyUsage.length];
+        System.arraycopy(keyUsage, 0, result, 0, keyUsage.length);
+        return result;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setExtendedKeyUsage(Set<String> keyUsage)
+                             throws IOException {
+        extendedKeyUsage = null;
+        if ((keyUsage == null) || (keyUsage.size() == 0)) {
+            return;
+        }
+        HashSet key_u = new HashSet();
+        Iterator it = keyUsage.iterator();
+        while (it.hasNext()) {
+            String usage = (String) it.next();
+            checkOID(usage);
+            key_u.add(usage);
+        }
+        extendedKeyUsage = Collections.unmodifiableSet(key_u);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Set<String> getExtendedKeyUsage() {
+        return extendedKeyUsage;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setMatchAllSubjectAltNames(boolean matchAllNames) {
+        this.matchAllNames = matchAllNames;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public boolean getMatchAllSubjectAltNames() {
+        return matchAllNames;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setSubjectAlternativeNames(Collection<List<?>> names)
+                                    throws IOException {
+        subjectAltNames = null;
+        if ((names == null) || (names.size() == 0)) {
+            return;
+        }
+        Iterator it = names.iterator();
+        while (it.hasNext()) {
+            List name = (List) it.next();
+            int tag = ((Integer) name.get(0)).intValue();
+            Object value = name.get(1);
+            if (value instanceof String) {
+                addSubjectAlternativeName(tag, (String) value);
+            } else if (value instanceof byte[]) {
+                addSubjectAlternativeName(tag, (byte[]) value);
+            } else {
+                throw new IOException(Messages.getString("security.57")); //$NON-NLS-1$
+            }
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void addSubjectAlternativeName(int tag, String name)
+                                                       throws IOException {
+        GeneralName alt_name = new GeneralName(tag, name);
+        // create only if there was not any errors
+        if (subjectAltNames == null) {
+            subjectAltNames = new ArrayList[9];
+        }
+        if (subjectAltNames[tag] == null) {
+            subjectAltNames[tag] = new ArrayList();
+        }
+        subjectAltNames[tag].add(alt_name);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void addSubjectAlternativeName(int tag, byte[] name)
+                                            throws IOException {
+        GeneralName alt_name = new GeneralName(tag, name);
+        // create only if there was not any errors
+        if (subjectAltNames == null) {
+            subjectAltNames = new ArrayList[9];
+        }
+        if (subjectAltNames[tag] == null) {
+            subjectAltNames[tag] = new ArrayList();
+        }
+        subjectAltNames[tag].add(alt_name);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Collection<List<?>> getSubjectAlternativeNames() {
+        if (subjectAltNames == null) {
+            return null;
+        }
+        ArrayList result = new ArrayList();
+        for (int tag=0; tag<9; tag++) {
+            if (subjectAltNames[tag] != null) {
+                Integer teg = new Integer(tag);
+                for (int name=0; name<subjectAltNames[tag].size(); name++) {
+                    Object neim = subjectAltNames[tag].get(name);
+                    if (neim instanceof byte[]) {
+                        byte[] arr_neim = (byte[]) neim;
+                        neim = new byte[arr_neim.length];
+                        System.arraycopy(arr_neim, 0, neim, 0, arr_neim.length);
+                    }
+                    List list = new ArrayList(2);
+                    list.add(teg);
+                    list.add(neim);
+                    result.add(list);
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setNameConstraints(byte[] bytes) throws IOException {
+        this.nameConstraints = (bytes == null)
+            ? null
+            : (NameConstraints) NameConstraints.ASN1.decode(bytes);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public byte[] getNameConstraints() {
+        return (nameConstraints == null)
+            ? null
+            : nameConstraints.getEncoded();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setBasicConstraints(int pathLen) {
+        if (pathLen < -2) {
+            throw new IllegalArgumentException(Messages.getString("security.58")); //$NON-NLS-1$
+        }
+        this.pathLen = pathLen;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public int getBasicConstraints() {
+        return pathLen;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setPolicy(Set<String> policies) throws IOException {
+        if (policies == null) {
+            this.policies = null;
+            return;
+        }
+        HashSet pols = new HashSet(policies.size());
+        Iterator it = policies.iterator();
+        while (it.hasNext()) {
+            String certPolicyId = (String) it.next();
+            checkOID(certPolicyId);
+            pols.add(certPolicyId);
+        }
+        this.policies = Collections.unmodifiableSet(pols);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Set<String> getPolicy() {
+        return policies;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void setPathToNames(Collection<List<?>> names)
+                                                        throws IOException {
+        pathToNames = null;
+        if ((names == null) || (names.size() == 0)) {
+            return;
+        }
+        Iterator it = names.iterator();
+        while (it.hasNext()) {
+            List name = (List) it.next();
+            int tag = ((Integer) name.get(0)).intValue();
+            Object value = name.get(1);
+            if (value instanceof String) {
+                addPathToName(tag, (String) value);
+            } else if (value instanceof byte[]) {
+                addPathToName(tag, (byte[]) value);
+            } else {
+                throw new IOException(Messages.getString("security.57")); //$NON-NLS-1$
+            }
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void addPathToName(int type, String name) throws IOException {
+        GeneralName path_name = new GeneralName(type, name);
+        // create only if there was not any errors
+        if (pathToNames == null) {
+            pathToNames = new ArrayList();
+        }
+        pathToNames.add(path_name);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public void addPathToName(int type, byte[] name) throws IOException {
+        GeneralName path_name= new GeneralName(type, name);
+        // create only if there was not any errors
+        if (pathToNames == null) {
+            pathToNames = new ArrayList();
+        }
+        pathToNames.add(path_name);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Collection<List<?>> getPathToNames() {
+        if (pathToNames == null) {
+            return null;
+        }
+        ArrayList result = new ArrayList();
+        Iterator it = pathToNames.iterator();
+        while (it.hasNext()) {
+            GeneralName name = (GeneralName) it.next();
+            result.add(name.getAsList());
+        }
+        return result;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public String toString() {
+        // For convenient reading of the string representation
+        // all of the fields named according to the rfc 3280
+        // (http://www.ietf.org/rfc/rfc3280.txt).
+
+        StringBuffer result = new StringBuffer();
+        result.append("X509CertSelector: \n["); //$NON-NLS-1$
+        if (this.certificateEquals != null) {
+            result.append("\n  certificateEquals: " + certificateEquals); //$NON-NLS-1$
+        }
+        if (this.serialNumber != null) {
+            //FIXME: needs DRL's BigInteger.toString implementation
+            //result.append("\n  serialNumber: " + serialNumber);
+        }
+        if (this.issuer != null) {
+            result.append("\n  issuer: " + issuer); //$NON-NLS-1$
+        }
+        if (this.subject != null) {
+            result.append("\n  subject: " + subject); //$NON-NLS-1$
+        }
+        if (this.subjectKeyIdentifier != null) {
+            result.append("\n  subjectKeyIdentifier: " //$NON-NLS-1$
+                    + getBytesAsString(subjectKeyIdentifier));
+        }
+        if (this.authorityKeyIdentifier != null) {
+            result.append("\n  authorityKeyIdentifier: " //$NON-NLS-1$
+                    + getBytesAsString(authorityKeyIdentifier));
+        }
+        if (this.certificateValid != null) {
+            result.append("\n  certificateValid: " + certificateValid); //$NON-NLS-1$
+        }
+        if (this.subjectPublicKeyAlgID != null) {
+            result.append("\n  subjectPublicKeyAlgID: " //$NON-NLS-1$
+                    + subjectPublicKeyAlgID);
+        }
+        if (this.privateKeyValid != null) {
+            result.append("\n  privateKeyValid: " + privateKeyValid); //$NON-NLS-1$
+        }
+        if (this.subjectPublicKey != null) {
+            result.append("\n  subjectPublicKey: " //$NON-NLS-1$
+                    + getBytesAsString(subjectPublicKey));
+        }
+        if (this.keyUsage != null) {
+            result.append("\n  keyUsage: \n  ["); //$NON-NLS-1$
+            String[] kuNames = new String[] {
+                "digitalSignature", "nonRepudiation", "keyEncipherment", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+                "dataEncipherment", "keyAgreement", "keyCertSign", "cRLSign", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+                "encipherOnly", "decipherOnly" //$NON-NLS-1$ //$NON-NLS-2$
+            };
+            for (int i=0; i<9; i++) {
+                if (keyUsage[i]) {
+                    result.append("\n    " + kuNames[i]); //$NON-NLS-1$
+                }
+            }
+            result.append("\n  ]"); //$NON-NLS-1$
+        }
+        if (this.extendedKeyUsage != null) {
+            result.append("\n  extendedKeyUsage: " //$NON-NLS-1$
+                    + extendedKeyUsage.toString());
+        }
+        result.append("\n  matchAllNames: " + matchAllNames); //$NON-NLS-1$
+        result.append("\n  pathLen: " + pathLen); //$NON-NLS-1$
+        if (this.subjectAltNames != null) {
+            result.append("\n  subjectAltNames:  \n  ["); //$NON-NLS-1$
+            for (int i=0; i<9; i++) {
+                List names = this.subjectAltNames[i];
+                if (names != null) {
+                    int size = names.size();
+                    for (int j=0; j<size; j++) {
+                        result.append("\n    " //$NON-NLS-1$
+                            + ((GeneralName)names.get(j)).toString());
+                    }
+                }
+            }
+            result.append("\n  ]"); //$NON-NLS-1$
+        }
+        if (this.nameConstraints != null) {
+        }
+        if (this.policies != null) {
+            result.append("\n  policies: " + policies.toString()); //$NON-NLS-1$
+        }
+        if (this.pathToNames != null) {
+            result.append("\n  pathToNames:  \n  ["); //$NON-NLS-1$
+            int size = pathToNames.size();
+            for (int i = 0; i < size; i++) {
+                result.append("\n    " //$NON-NLS-1$
+                    + ((GeneralName)pathToNames.get(i)).toString());
+            }
+        }
+        result.append("\n]"); //$NON-NLS-1$
+        return result.toString();
+    }
+
+    private String getBytesAsString(byte[] data) {
+        String result = ""; //$NON-NLS-1$
+        for (int i=0; i<data.length; i++) {
+            String tail = Integer.toHexString(0x00ff & data[i]);
+            if (tail.length() == 1) {
+                tail = "0" + tail; //$NON-NLS-1$
+            }
+            result += tail + " "; //$NON-NLS-1$
+        }
+        return result;
+    }
+
+    private byte[] getExtensionValue(X509Certificate cert, String oid) {
+        try {
+            byte[] bytes = cert.getExtensionValue(oid);
+            if (bytes == null) {
+                return null;
+            }
+            return (byte[]) ASN1OctetString.getInstance().decode(bytes);
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public boolean match(Certificate certificate) {
+        if (! (certificate instanceof X509Certificate)) {
+            return false;
+        }
+
+        X509Certificate cert = (X509Certificate) certificate;
+        if ((certificateEquals != null) &&
+            !certificateEquals.equals(cert)) {
+            return false;
+        }
+        if ((serialNumber != null) &&
+            !serialNumber.equals(cert.getSerialNumber())) {
+            return false;
+        }
+        if ((issuer != null) &&
+            !issuer.equals(cert.getIssuerX500Principal())) {
+            return false;
+        }
+        if ((subject != null) &&
+            !subject.equals(cert.getSubjectX500Principal())) {
+            return false;
+        }
+        if ((subjectKeyIdentifier != null) &&
+            !Arrays.equals(subjectKeyIdentifier,
+            // Here and later all of the extension OIDs 
+            // are taken from rfc 3280 (http://www.ietf.org/rfc/rfc3280.txt)
+                           getExtensionValue(cert, "2.5.29.14"))) { //$NON-NLS-1$
+            return false;
+        }
+        if ((authorityKeyIdentifier != null) &&
+            !Arrays.equals(authorityKeyIdentifier,
+                           getExtensionValue(cert, "2.5.29.35"))) { //$NON-NLS-1$
+            return false;
+        }
+        if (certificateValid != null) {
+            try {
+                cert.checkValidity(certificateValid);
+            } catch(CertificateExpiredException e) {
+                return false;
+            } catch(CertificateNotYetValidException e) {
+                return false;
+            }
+        }
+        if (privateKeyValid != null) {
+            try {
+                byte[] bytes = getExtensionValue(cert, "2.5.29.16"); //$NON-NLS-1$
+                if (bytes == null) {
+                    return false;
+                }
+                PrivateKeyUsagePeriod pkup = (PrivateKeyUsagePeriod) 
+                                    PrivateKeyUsagePeriod.ASN1.decode(bytes);
+                Date notBefore = pkup.getNotBefore();
+                Date notAfter = pkup.getNotAfter();
+                if ((notBefore == null) && (notAfter == null)) {
+                    return false;
+                }
+                if ((notBefore != null)
+                    && notBefore.compareTo(privateKeyValid) > 0) {
+                    return false;
+                }
+                if ((notAfter != null)
+                    && notAfter.compareTo(privateKeyValid) < 0) {
+                    return false;
+                }
+            } catch (IOException e) {
+                return false;
+            }
+        }
+        if (subjectPublicKeyAlgID  != null) {
+            try {
+                byte[] encoding = cert.getPublicKey().getEncoded();
+                AlgorithmIdentifier ai = ((SubjectPublicKeyInfo) 
+                        SubjectPublicKeyInfo.ASN1.decode(encoding))
+                        .getAlgorithmIdentifier();
+                if (!subjectPublicKeyAlgID.equals(ai.getAlgorithm())) {
+                    return false;
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+                return false;
+            }
+        }
+        if (subjectPublicKey != null) {
+            if (!Arrays.equals(subjectPublicKey,
+                               cert.getPublicKey().getEncoded())) {
+                return false;
+            }
+        }
+        if (keyUsage != null) {
+            boolean[] ku = cert.getKeyUsage();
+            if (ku != null) {
+                int i = 0;
+                int min_length = (ku.length < keyUsage.length) ? ku.length
+                        : keyUsage.length;
+                for (; i < min_length; i++) {
+                    if (keyUsage[i] && !ku[i]) {
+                        // the specified keyUsage allows,
+                        // but certificate does not.
+                        return false;
+                    }
+                }
+                for (; i<keyUsage.length; i++) {
+                    if (keyUsage[i]) {
+                        return false;
+                    }
+                }
+            }
+        }
+        if (extendedKeyUsage != null) {
+            try {
+                List keyUsage = cert.getExtendedKeyUsage();
+                if (keyUsage != null) {
+                    if (!keyUsage.containsAll(extendedKeyUsage)) {
+                        return false;
+                    }
+                }
+            } catch (CertificateParsingException e) {
+                return false;
+            }
+        }
+        if (pathLen != -1) {
+            int p_len = cert.getBasicConstraints();
+            if ((pathLen < 0) && (p_len >= 0)) {
+                // need end-entity but got CA
+                return false;
+            }
+            if ((pathLen > 0) && (pathLen > p_len)) {
+                // allowed _pathLen is small
+                return false;
+            }
+        }
+        if (subjectAltNames != null) {
+            PASSED:
+            try {
+                byte[] bytes = getExtensionValue(cert, "2.5.29.17"); //$NON-NLS-1$
+                if (bytes == null) {
+                    return false;
+                }
+                List sans = ((GeneralNames) GeneralNames.ASN1.decode(bytes))
+                            .getNames();
+                if ((sans == null) || (sans.size() == 0)) {
+                    return false;
+                }
+                boolean[][] map = new boolean[9][];
+                // initialize the check map
+                for (int i=0; i<9; i++) {
+                    map[i] = (subjectAltNames[i] == null)
+                                ? new boolean[0]
+                                : new boolean[subjectAltNames[i].size()];
+                }
+                Iterator it = sans.iterator();
+                while (it.hasNext()) {
+                    GeneralName name = (GeneralName) it.next();
+                    int tag = name.getTag();
+                    for (int i=0; i<map[tag].length; i++) {
+                        if (((GeneralName) subjectAltNames[tag].get(i))
+                                                            .equals(name)) {
+                            if (!matchAllNames) {
+                                break PASSED;
+                            }
+                            map[tag][i] = true;
+                        }
+                    }
+                }
+                if (!matchAllNames) {
+                    // there was not any match
+                    return false;
+                }
+                // else check the map
+                for (int tag=0; tag<9; tag++) {
+                    for (int name=0; name<map[tag].length; name++) {
+                        if (!map[tag][name]) {
+                            return false;
+                        }
+                    }
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+                return false;
+            }
+        }
+        if (nameConstraints != null) {
+            if (!nameConstraints.isAcceptable(cert)) {
+                return false;
+            }
+        }
+        if (policies != null) {
+            byte[] bytes = getExtensionValue(cert, "2.5.29.32"); //$NON-NLS-1$
+            if (bytes == null) {
+                return false;
+            }
+            if (policies.size() == 0) {
+                // if certificate has such extension than it has at least
+                // one policy in it.
+                return true;
+            }
+            PASSED:
+            try {
+                List policyInformations = ((CertificatePolicies) 
+                        CertificatePolicies.ASN1.decode(bytes))
+                        .getPolicyInformations();
+                Iterator it = policyInformations.iterator();
+                while (it.hasNext()) {
+                    if (policies.contains(((PolicyInformation) it.next())
+                                          .getPolicyIdentifier())) {
+                        break PASSED;
+                    }
+                }
+                return false;
+            } catch (IOException e) {
+                // the extension is invalid
+                return false;
+            }
+        }
+        if (pathToNames != null) {
+            byte[] bytes = getExtensionValue(cert, "2.5.29.30"); //$NON-NLS-1$
+            if (bytes != null) {
+                NameConstraints nameConstraints;
+                try {
+                    nameConstraints =
+                        (NameConstraints) NameConstraints.ASN1.decode(bytes);
+                } catch (IOException e) {
+                    // the extension is invalid;
+                    return false;
+                }
+                if (!nameConstraints.isAcceptable(pathToNames)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Object clone() {
+        X509CertSelector result = new X509CertSelector();
+        result.certificateEquals = this.certificateEquals;
+        result.serialNumber = this.serialNumber;
+        result.issuer = this.issuer;
+        result.subject = this.subject;
+        if (this.subjectKeyIdentifier != null) {
+            result.subjectKeyIdentifier =
+                new byte[this.subjectKeyIdentifier.length];
+            System.arraycopy(this.subjectKeyIdentifier, 0,
+                    result.subjectKeyIdentifier, 0,
+                    this.subjectKeyIdentifier.length);
+        }
+        if (this.authorityKeyIdentifier != null) {
+            result.authorityKeyIdentifier =
+                new byte[this.authorityKeyIdentifier.length];
+            System.arraycopy(this.authorityKeyIdentifier, 0,
+                    result.authorityKeyIdentifier, 0,
+                    this.authorityKeyIdentifier.length);
+        }
+        result.certificateValid = this.certificateValid;
+        result.subjectPublicKeyAlgID = this.subjectPublicKeyAlgID;
+        result.privateKeyValid = this.privateKeyValid;
+        if (this.subjectPublicKey != null) {
+            result.subjectPublicKey = new byte[this.subjectPublicKey.length];
+            System.arraycopy(this.subjectPublicKey, 0, result.subjectPublicKey,
+                    0, this.subjectPublicKey.length);
+        }
+        if (this.keyUsage != null) {
+            result.keyUsage = new boolean[this.keyUsage.length];
+            System.arraycopy(this.keyUsage, 0, result.keyUsage, 0,
+                    this.keyUsage.length);
+        }
+        result.extendedKeyUsage = (this.extendedKeyUsage == null)
+            ? null
+            : new HashSet(this.extendedKeyUsage);
+        result.matchAllNames = this.matchAllNames;
+        result.pathLen = this.pathLen;
+        if (this.subjectAltNames != null) {
+            result.subjectAltNames = new ArrayList[9];
+            for (int i=0; i<9; i++) {
+                if (this.subjectAltNames[i] != null) {
+                    result.subjectAltNames[i] =
+                        new ArrayList(this.subjectAltNames[i]);
+                }
+            }
+        }
+        result.nameConstraints = this.nameConstraints;
+        result.policies = (this.policies == null)
+            ? null
+            : new HashSet(this.policies);
+        result.pathToNames = (this.pathToNames == null)
+            ? null
+            : new ArrayList(this.pathToNames);
+        result.subjectPublicKeyImpl = this.subjectPublicKeyImpl;
+
+        return result;
+    }
+}
+
diff --git a/libcore/security/src/main/java/java/security/cert/X509Certificate.java b/libcore/security/src/main/java/java/security/cert/X509Certificate.java
new file mode 100644
index 0000000..aa3d7a5
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/X509Certificate.java
@@ -0,0 +1,205 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.io.ByteArrayInputStream;
+import java.math.BigInteger;
+import java.security.Principal;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref
+ */
+public abstract class X509Certificate
+        extends Certificate implements X509Extension {
+
+    private static final long serialVersionUID = -2491127588187038216L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    protected X509Certificate() {
+        super("X.509"); //$NON-NLS-1$
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract void checkValidity()
+            throws CertificateExpiredException, CertificateNotYetValidException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract void checkValidity(Date date)
+            throws CertificateExpiredException, CertificateNotYetValidException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract int getVersion();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract BigInteger getSerialNumber();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract Principal getIssuerDN() ;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public X500Principal getIssuerX500Principal() {
+
+        try {
+            // TODO if there is no X.509 certificate provider installed
+            // should we try to access Harmony X509CertImpl via classForName?
+            CertificateFactory factory = CertificateFactory
+                    .getInstance("X.509"); //$NON-NLS-1$
+
+            X509Certificate cert = (X509Certificate) factory
+                    .generateCertificate(new ByteArrayInputStream(getEncoded()));
+
+            return cert.getIssuerX500Principal();
+
+        } catch (Exception e) {
+            throw new RuntimeException(Messages.getString("security.59"), e); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract Principal getSubjectDN();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public X500Principal getSubjectX500Principal() {
+
+        try {
+            // TODO if there is no X.509 certificate provider installed
+            // should we try to access Harmony X509CertImpl via classForName?
+            CertificateFactory factory = CertificateFactory
+                    .getInstance("X.509"); //$NON-NLS-1$
+
+            X509Certificate cert = (X509Certificate) factory
+                    .generateCertificate(new ByteArrayInputStream(getEncoded()));
+
+            return cert.getSubjectX500Principal();
+
+        } catch (Exception e) {
+            throw new RuntimeException(Messages.getString("security.5A"), e); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract Date getNotBefore();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract Date getNotAfter();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract byte[] getTBSCertificate()
+                                    throws CertificateEncodingException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract byte[] getSignature();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract String getSigAlgName();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract String getSigAlgOID();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract byte[] getSigAlgParams();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract boolean[] getIssuerUniqueID();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract boolean[] getSubjectUniqueID();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract boolean[] getKeyUsage();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public List<String> getExtendedKeyUsage()
+                        throws CertificateParsingException {
+        return null;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract int getBasicConstraints();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Collection<List<?>> getSubjectAlternativeNames()
+                                    throws CertificateParsingException {
+        return null;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Collection<List<?>> getIssuerAlternativeNames()
+                                    throws CertificateParsingException {
+        return null;
+    }
+}
+
diff --git a/libcore/security/src/main/java/java/security/cert/X509Extension.java b/libcore/security/src/main/java/java/security/cert/X509Extension.java
new file mode 100644
index 0000000..416fe44
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/X509Extension.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.cert;
+
+import java.util.Set;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface X509Extension {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Set<String> getCriticalExtensionOIDs();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public byte[] getExtensionValue(String oid);
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Set<String> getNonCriticalExtensionOIDs();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public boolean hasUnsupportedCriticalExtension();
+}
diff --git a/libcore/security/src/main/java/java/security/cert/package.html b/libcore/security/src/main/java/java/security/cert/package.html
new file mode 100644
index 0000000..4212857
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/cert/package.html
@@ -0,0 +1,20 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
+</head>
+<html>
+<body>
+<p>
+This package provides all the classes and all the interfaces needed to generate, administer and verify
+X.509 certificates.
+Functionality for parsing certificate, extracting information from them, validating and
+verifying the information they contains are provided.
+Exception are generated if the certificate's encoding is broken
+{@link java.security.cert.CertificateEncodingException}, if the certificate's time stamp is not valid
+{@link java.security.cert.CertificateExpiredException}, if the validation's path is false
+{@link java.security.cert.CertPathValidatorException}.
+
+All the the functionality to check the different entries and extension fields of X.509 certificates are provided.
+</p>
+</body>
+</html>
diff --git a/libcore/security/src/main/java/java/security/interfaces/DSAKey.java b/libcore/security/src/main/java/java/security/interfaces/DSAKey.java
new file mode 100644
index 0000000..0c443db
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/interfaces/DSAKey.java
@@ -0,0 +1,36 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.interfaces;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface DSAKey {
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public DSAParams getParams();
+
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/interfaces/DSAKeyPairGenerator.java b/libcore/security/src/main/java/java/security/interfaces/DSAKeyPairGenerator.java
new file mode 100644
index 0000000..c2a2dfb
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/interfaces/DSAKeyPairGenerator.java
@@ -0,0 +1,46 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.interfaces;
+
+import java.security.InvalidParameterException;
+import java.security.SecureRandom;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface DSAKeyPairGenerator {
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public void initialize(DSAParams params, SecureRandom random)
+            throws InvalidParameterException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public void initialize(int modlen, boolean genParams, SecureRandom random)
+            throws InvalidParameterException;
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/interfaces/DSAParams.java b/libcore/security/src/main/java/java/security/interfaces/DSAParams.java
new file mode 100644
index 0000000..3da9236
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/interfaces/DSAParams.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.interfaces;
+
+import java.math.BigInteger;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface DSAParams {
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public BigInteger getG();
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public BigInteger getP();
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public BigInteger getQ();
+
+}
+
diff --git a/libcore/security/src/main/java/java/security/interfaces/DSAPrivateKey.java b/libcore/security/src/main/java/java/security/interfaces/DSAPrivateKey.java
new file mode 100644
index 0000000..2ad156e
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/interfaces/DSAPrivateKey.java
@@ -0,0 +1,45 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.interfaces;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface DSAPrivateKey extends DSAKey, PrivateKey {
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public static final long serialVersionUID = 7776497482533790279L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public BigInteger getX();
+
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/interfaces/DSAPublicKey.java b/libcore/security/src/main/java/java/security/interfaces/DSAPublicKey.java
new file mode 100644
index 0000000..0da7beb
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/interfaces/DSAPublicKey.java
@@ -0,0 +1,43 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.interfaces;
+
+import java.math.BigInteger;
+import java.security.PublicKey;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface DSAPublicKey extends DSAKey, PublicKey {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public static final long serialVersionUID = 1234526332779022332L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getY();
+
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/interfaces/ECKey.java b/libcore/security/src/main/java/java/security/interfaces/ECKey.java
new file mode 100644
index 0000000..950a533
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/interfaces/ECKey.java
@@ -0,0 +1,37 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.interfaces;
+
+import java.security.spec.ECParameterSpec;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface ECKey {
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public ECParameterSpec getParams();
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/interfaces/ECPrivateKey.java b/libcore/security/src/main/java/java/security/interfaces/ECPrivateKey.java
new file mode 100644
index 0000000..fcd18be
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/interfaces/ECPrivateKey.java
@@ -0,0 +1,42 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.interfaces;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface ECPrivateKey extends PrivateKey, ECKey {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public static final long serialVersionUID = -7896394956925609184L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getS();
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/interfaces/ECPublicKey.java b/libcore/security/src/main/java/java/security/interfaces/ECPublicKey.java
new file mode 100644
index 0000000..d138037
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/interfaces/ECPublicKey.java
@@ -0,0 +1,42 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.interfaces;
+
+import java.security.spec.ECPoint;
+import java.security.PublicKey;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface ECPublicKey extends PublicKey, ECKey {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public static final long serialVersionUID = -3314988629879632826L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public ECPoint getW();
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/interfaces/RSAKey.java b/libcore/security/src/main/java/java/security/interfaces/RSAKey.java
new file mode 100644
index 0000000..fe34977
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/interfaces/RSAKey.java
@@ -0,0 +1,36 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.interfaces;
+
+import java.math.BigInteger;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface RSAKey {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getModulus();
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java b/libcore/security/src/main/java/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java
new file mode 100644
index 0000000..5cdf0e1
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java
@@ -0,0 +1,72 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.interfaces;
+
+import java.math.BigInteger;
+import java.security.spec.RSAOtherPrimeInfo;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface RSAMultiPrimePrivateCrtKey extends RSAPrivateKey {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public static final long serialVersionUID = 618058533534628008L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getCrtCoefficient();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public RSAOtherPrimeInfo[] getOtherPrimeInfo();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getPrimeP();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getPrimeQ();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getPrimeExponentP();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getPrimeExponentQ();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getPublicExponent();
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/interfaces/RSAPrivateCrtKey.java b/libcore/security/src/main/java/java/security/interfaces/RSAPrivateCrtKey.java
new file mode 100644
index 0000000..9f11582
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/interfaces/RSAPrivateCrtKey.java
@@ -0,0 +1,73 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.interfaces;
+
+import java.math.BigInteger;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface RSAPrivateCrtKey extends RSAPrivateKey {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public static final long serialVersionUID = -5682214253527700368L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public BigInteger getCrtCoefficient();
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public BigInteger getPrimeP();
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public BigInteger getPrimeQ();
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public BigInteger getPrimeExponentP();
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public BigInteger getPrimeExponentQ();
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public BigInteger getPublicExponent();
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/interfaces/RSAPrivateKey.java b/libcore/security/src/main/java/java/security/interfaces/RSAPrivateKey.java
new file mode 100644
index 0000000..707d0c2
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/interfaces/RSAPrivateKey.java
@@ -0,0 +1,43 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.interfaces;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface RSAPrivateKey extends PrivateKey, RSAKey {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public static final long serialVersionUID = 5187144804936595022L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public BigInteger getPrivateExponent();
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/interfaces/RSAPublicKey.java b/libcore/security/src/main/java/java/security/interfaces/RSAPublicKey.java
new file mode 100644
index 0000000..7a87826
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/interfaces/RSAPublicKey.java
@@ -0,0 +1,44 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.interfaces;
+
+import java.math.BigInteger;
+import java.security.PublicKey;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface RSAPublicKey extends PublicKey, RSAKey {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public static final long serialVersionUID = -8727434096241101194L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public BigInteger getPublicExponent();
+
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/interfaces/package.html b/libcore/security/src/main/java/java/security/interfaces/package.html
new file mode 100644
index 0000000..d2772a6
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/interfaces/package.html
@@ -0,0 +1,14 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
+</head>
+<html>
+<body>
+<p>
+This package provides the interfaces needed to generate:
+(1) Keys for the RSA asymmetric encryption algorithm using the PKCS#1 standard;
+(2) Keys for the Digital Signature Algorithm (DSA) specified by FIPS-186;
+(3) Keys for a generic Elliptic Curve asymmetric encryption algorithm.
+</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/package.html b/libcore/security/src/main/java/java/security/package.html
new file mode 100644
index 0000000..6a87bc3
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/package.html
@@ -0,0 +1,15 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
+</head>
+<html>
+<body>
+<p>
+This package provides all the classes and all the interfaces needed by Java security framework.
+Functionality for signing jar files Class {@link java.security.Signer}; for generating
+public and private key for asymmetric encryption algorithm {@link java.security.PublicKey} and
+{@link java.security.PrivateKey} are provided.
+All the the functionality to expand the priviledges within the AccessController are also defined here.
+</p>
+</body>
+</html>
diff --git a/libcore/security/src/main/java/java/security/security.properties b/libcore/security/src/main/java/java/security/security.properties
new file mode 100644
index 0000000..cc16be7
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/security.properties
@@ -0,0 +1,120 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+# 
+#     http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This is the system security properties file
+# It should be named: ${java.home}/lib/security/java.security
+
+
+#
+# Providers
+# See also: J2SE doc. "How to Implement a Provider for the JavaTM Cryptography Architecture"
+#
+# Harmony providers
+security.provider.1=org.apache.harmony.security.provider.cert.DRLCertFactory
+security.provider.2=org.apache.harmony.security.provider.crypto.CryptoProvider
+security.provider.3=org.apache.harmony.xnet.provider.jsse.JSSEProvider
+# Other Open Source providers
+security.provider.4=org.bouncycastle.jce.provider.BouncyCastleProvider
+
+#
+# Class to instantiate as a default Configuration implementation
+# See specification for javax.security.auth.login.Configuration class.
+#
+login.configuration.provider=org.apache.harmony.auth.login.DefaultConfiguration
+
+
+#
+# Flag to enable/disable append/overwrite this properties file by the 
+# extra properties file passed on the command line with
+# -Djava.security.properties=<file|url> or -Djava.security.properties==<file|url>
+# Possible values: true/false.
+#
+security.allowCustomPropertiesFile=true
+
+
+# Class to instantiate as the default system Policy.
+# The class should be available via bootclasspath.
+# See specification for java.security.Policy class.
+policy.provider=org.apache.harmony.security.fortress.DefaultPolicy
+
+
+# The default is to have a single system-wide policy file,
+# and an optional policy file in the user's home directory.
+# It is possible to specify any number of policy files, via policy.url.n keys.
+# See also: "JavaTM 2 Platform Security Architecture.", chapter 3. Permissions and Security Policy
+policy.url.1=file:/${java.home}/lib/security/java.policy
+policy.url.2=file:/${user.home}/.java.policy
+
+
+# Flag to enable/disable properties expansion (${...}) in policy files. 
+# Possible values: true/false.
+# See also: "JavaTM 2 Platform Security Architecture.", chapter 3. Permissions and Security Policy
+policy.expandProperties=true
+
+
+# Flag to enable/disable an extra policy to be passed on the command line
+# with -Djava.security.policy=<file|url>. Possible values: true/false.
+# See also: "JavaTM 2 Platform Security Architecture.", chapter 3. Permissions and Security Policy
+policy.allowSystemProperty=true
+
+
+# A comma-separated list of package prefixes that require 
+# extra protection at ClassLoader's level. 
+# See java/lang/SecurityManager#checkPackageAccess for more details.
+package.access=org.apache.harmony.security.fortress.,com.intel.fortress.,com.ibm.oti.
+
+
+# Class to instantiate as default JGSS manager.
+jgss.spi.manager=
+
+
+# The default SSLSocketFactory and SSLServerSocketFactory provider implementations.
+# See specification for 
+# javax/net/ssl/SSLSocketFactory.html#getDefault()
+# javax/net/ssl/SSLServerSocketFactory.html#getDefault()
+
+# BEGIN android-removed
+ssl.SocketFactory.provider=org.apache.harmony.xnet.provider.jsse.OpenSSLSocketFactoryImpl
+# END android-removed
+
+# BEGIN android-added
+# Use the definition above to get the new, OpenSSL-based SSL implementation,
+# or use this one to get the old, Android-based SSL implementation.
+# ssl.SocketFactory.provider=javax.net.ssl.OldSSLSocketFactory
+# END android-added
+
+# For SSL server sockets, there's only the new, OpenSSL-based implementation.
+ssl.ServerSocketFactory.provider=org.apache.harmony.xnet.provider.jsse.OpenSSLServerSocketFactoryImpl
+
+# Default KeyStore type.
+# See specification for java/security/KeyStore.html#getDefaultType()
+keystore.type=BKS
+
+
+# Default KeyManagerFactory and TrustManagerFactory algorithms. 
+# See specification for
+# javax/net/ssl/KeyManagerFactory.html#getDefaultAlgorithm()
+# javax/net/ssl/TrustManagerFactory.html#getDefaultAlgorithm()
+ssl.KeyManagerFactory.algorithm=X509
+ssl.TrustManagerFactory.algorithm=X509
+
+# system.scope is used to specify implementation class of IdentityScope
+# this class should can be loaded by boot classloader
+system.scope=org.apache.harmony.security.SystemScope
+
+# BEGIN android-added
+# The following non-standard property controls peer certificate validation.
+ssl.disablePeerCertificateChainVerification=false
+# END android-added
diff --git a/libcore/security/src/main/java/java/security/spec/AlgorithmParameterSpec.java b/libcore/security/src/main/java/java/security/spec/AlgorithmParameterSpec.java
new file mode 100644
index 0000000..0f1df72
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/AlgorithmParameterSpec.java
@@ -0,0 +1,30 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface AlgorithmParameterSpec {
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/spec/DSAParameterSpec.java b/libcore/security/src/main/java/java/security/spec/DSAParameterSpec.java
new file mode 100644
index 0000000..c331c1f
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/DSAParameterSpec.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+import java.math.BigInteger;
+import java.security.interfaces.DSAParams;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class DSAParameterSpec implements AlgorithmParameterSpec, DSAParams {
+    // Prime
+    private final BigInteger p;
+    // Sub-prime
+    private final BigInteger q;
+    // Base
+    private final BigInteger g;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public DSAParameterSpec(BigInteger p, BigInteger q, BigInteger g) {
+        this.p = p;
+        this.q = q;
+        this.g = g;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getG() {
+        return g;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getP() {
+        return p;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getQ() {
+        return q;
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/spec/DSAPrivateKeySpec.java b/libcore/security/src/main/java/java/security/spec/DSAPrivateKeySpec.java
new file mode 100644
index 0000000..d095eaa
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/DSAPrivateKeySpec.java
@@ -0,0 +1,79 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+import java.math.BigInteger;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class DSAPrivateKeySpec implements KeySpec {
+    // Private key
+    private final BigInteger x;
+    // Prime
+    private final BigInteger p;
+    // Sub-prime
+     private final BigInteger q;
+    // Base
+    private final BigInteger g;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public DSAPrivateKeySpec(BigInteger x, BigInteger p,
+            BigInteger q, BigInteger g) {
+        this.x = x;
+        this.p = p;
+        this.q = q;
+        this.g = g;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getG() {
+        return g;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getP() {
+        return p;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getQ() {
+        return q;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getX() {
+        return x;
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/spec/DSAPublicKeySpec.java b/libcore/security/src/main/java/java/security/spec/DSAPublicKeySpec.java
new file mode 100644
index 0000000..e37430d
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/DSAPublicKeySpec.java
@@ -0,0 +1,79 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+import java.math.BigInteger;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class DSAPublicKeySpec implements KeySpec {
+    // Public key
+    private final BigInteger y;
+    // Prime
+    private final BigInteger p;
+    // Sub-prime
+    private final BigInteger q;
+    // Base
+    private final BigInteger g;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public DSAPublicKeySpec(BigInteger y, BigInteger p,
+            BigInteger q, BigInteger g) {
+        this.y = y;
+        this.p = p;
+        this.q = q;
+        this.g = g;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getG() {
+        return g;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getP() {
+        return p;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getQ() {
+        return q;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getY() {
+        return y;
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/spec/ECField.java b/libcore/security/src/main/java/java/security/spec/ECField.java
new file mode 100644
index 0000000..22109a3
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/ECField.java
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface ECField {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    int getFieldSize();
+}
diff --git a/libcore/security/src/main/java/java/security/spec/ECFieldF2m.java b/libcore/security/src/main/java/java/security/spec/ECFieldF2m.java
new file mode 100644
index 0000000..a2f13b1
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/ECFieldF2m.java
@@ -0,0 +1,216 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class ECFieldF2m implements ECField {
+    // Mid terms array length for trinomial basis
+    private static final int TPB_MID_LEN = 1;
+    // Mid terms array length for pentanomial basis
+    private static final int PPB_MID_LEN = 3;
+    // All terms number for trinomial basis
+    private static final int TPB_LEN = TPB_MID_LEN + 2;
+    // All terms number for pentanomial basis
+    private static final int PPB_LEN = PPB_MID_LEN + 2;
+    // m value
+    private final int m;
+    // Reduction polynomial
+    private final BigInteger rp;
+    // Mid term(s) of reduction polynomial
+    private final int[] ks;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public ECFieldF2m(int m) {
+        this.m = m;
+        if (this.m <= 0) {
+            throw new IllegalArgumentException(Messages.getString("security.75")); //$NON-NLS-1$
+        }
+        this.rp = null;
+        this.ks = null;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public ECFieldF2m(int m, BigInteger rp) {
+        this.m = m;
+        if (this.m <= 0) {
+            throw new IllegalArgumentException(Messages.getString("security.75")); //$NON-NLS-1$
+        }
+        this.rp = rp;
+        if (this.rp == null) {
+            throw new NullPointerException(Messages.getString("security.76")); //$NON-NLS-1$
+        }
+        // the leftmost bit must be (m+1)-th one,
+        // set bits count must be 3 or 5,
+        // bits 0 and m must be set
+        int rp_bc = this.rp.bitCount();
+        if ((this.rp.bitLength() != (m+1)) ||
+            (rp_bc != TPB_LEN && rp_bc != PPB_LEN) ||
+            (!this.rp.testBit(0) || !this.rp.testBit(m)) ) {
+            throw new IllegalArgumentException(Messages.getString("security.77")); //$NON-NLS-1$
+        }
+
+        // setup ks using rp:
+        // allocate for mid terms only
+        ks = new int[rp_bc-2];
+        // find midterm orders and set ks accordingly
+        BigInteger rpTmp = rp.clearBit(0);
+        for (int i=ks.length-1; i>=0; i-- ) {
+            ks[i] = rpTmp.getLowestSetBit();
+            rpTmp = rpTmp.clearBit(ks[i]);
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public ECFieldF2m(int m, int[] ks) {
+        this.m = m;
+        if (this.m <= 0) {
+            throw new IllegalArgumentException(Messages.getString("security.75")); //$NON-NLS-1$
+        }
+        // Defensively copies array parameter
+        // to prevent subsequent modification.
+        // NPE as specified if ks is null
+        this.ks = new int[ks.length];
+        System.arraycopy(ks, 0, this.ks, 0, this.ks.length);
+
+        // no need to check for null already
+        if (this.ks.length != TPB_MID_LEN && this.ks.length != PPB_MID_LEN) {
+            // must be either trinomial or pentanomial basis
+            throw new IllegalArgumentException(Messages.getString("security.78")); //$NON-NLS-1$
+        }
+        // trinomial basis:
+        // check that m > k >= 1, where k is ks[0]
+        // pentanomial basis:
+        // check that m > k3 > k2 > k1 >= 1
+        // and kx in descending order, where
+        // k3 is ks[0], k2 is ks[1], k1 is ks[2]
+        boolean checkFailed = false;
+        int prev = this.m;
+        for (int i=0; i<this.ks.length; i++) {
+            if (this.ks[i] < prev) {
+                prev = this.ks[i];
+                continue;
+            }
+            checkFailed = true;
+            break;
+        }
+        if (checkFailed || prev < 1) {
+            throw new IllegalArgumentException(Messages.getString("security.79")); //$NON-NLS-1$
+        }
+
+        // Setup rp using ks:
+        // bits 0 and m always set
+        BigInteger rpTmp = BigInteger.ONE.setBit(this.m);
+        // set remaining bits according to ks
+        for (int i=0; i<this.ks.length; i++) {
+            rpTmp = rpTmp.setBit(this.ks[i]);
+        }
+        rp = rpTmp;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public boolean equals(Object obj) {
+        // object equals to itself
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof ECFieldF2m) {
+            ECFieldF2m o = (ECFieldF2m)obj;
+            // check m
+            if (this.m == o.m) {
+                // check rp
+                if (this.rp == null) {
+                    if (o.rp == null) {
+                        // fields both with normal basis
+                        return true;
+                    }
+                } else {
+                    // at least this field with polynomial basis
+                    // check that rp match
+                    // return this.rp.equals(o.rp);
+                    return Arrays.equals(this.ks, o.ks);
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public int getFieldSize() {
+        return m;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public int getM() {
+        return m;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public int[] getMidTermsOfReductionPolynomial() {
+        // Defensively copies private array
+        // to prevent subsequent modification
+        // was: return ks == null ? null : (int[])ks.clone();
+        if (ks == null) {
+            return null;
+        } else {
+            int[] ret = new int[ks.length];
+            System.arraycopy(ks, 0, ret, 0, ret.length);
+            return ret;
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getReductionPolynomial() {
+        return rp;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public int hashCode() {
+        return rp == null ? m : m + rp.hashCode();
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/spec/ECFieldFp.java b/libcore/security/src/main/java/java/security/spec/ECFieldFp.java
new file mode 100644
index 0000000..6328ea9
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/ECFieldFp.java
@@ -0,0 +1,85 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+import java.math.BigInteger;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class ECFieldFp implements ECField {
+    // Prime
+    private final BigInteger p;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public ECFieldFp(BigInteger p) {
+        this.p = p;
+
+        if (this.p == null) {
+            throw new NullPointerException(Messages.getString("security.83", "p")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if (this.p.signum() != 1) {
+            throw new IllegalArgumentException(Messages.getString("security.86", "p")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public int getFieldSize() {
+        return p.bitLength();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getP() {
+        return p;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public boolean equals(Object obj) {
+        // object equals itself
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof ECFieldFp) {
+            return (this.p.equals(((ECFieldFp)obj).p));
+        }
+        return false;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public int hashCode() {
+        return p.hashCode();
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/spec/ECGenParameterSpec.java b/libcore/security/src/main/java/java/security/spec/ECGenParameterSpec.java
new file mode 100644
index 0000000..4be5283
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/ECGenParameterSpec.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class ECGenParameterSpec implements AlgorithmParameterSpec {
+    // Standard (or predefined) name for EC domain
+    // parameters to be generated
+    private final String name;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public ECGenParameterSpec(String name) {
+        this.name = name;
+        if (this.name == null) {
+            throw new NullPointerException(Messages.getString("security.83", "name")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public String getName() {
+        return name;
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/spec/ECParameterSpec.java b/libcore/security/src/main/java/java/security/spec/ECParameterSpec.java
new file mode 100644
index 0000000..f438844
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/ECParameterSpec.java
@@ -0,0 +1,100 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+import java.math.BigInteger;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class ECParameterSpec implements AlgorithmParameterSpec {
+    // Elliptic curve for which this is parameter
+    private final EllipticCurve curve;
+    // Distinguished point on the elliptic curve called generator or base point
+    private final ECPoint generator;
+    // Order of the generator
+    private final BigInteger order;
+    // Cofactor
+    private final int cofactor;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public ECParameterSpec(EllipticCurve curve, ECPoint generator,
+            BigInteger order, int cofactor) {
+        this.curve = curve;
+        this.generator = generator;
+        this.order = order;
+        this.cofactor = cofactor;
+        // throw NullPointerException if curve, generator or order is null
+        if (this.curve == null) {
+            throw new NullPointerException(Messages.getString("security.83", "curve")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if (this.generator == null) {
+            throw new NullPointerException(Messages.getString("security.83", "generator")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if (this.order == null) {
+            throw new NullPointerException(Messages.getString("security.83", "order")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        // throw IllegalArgumentException if order or cofactor is not positive
+        if (!(this.order.compareTo(BigInteger.ZERO) > 0)) {
+            throw new
+            IllegalArgumentException(Messages.getString("security.86", "order")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if (!(this.cofactor > 0)) {
+            throw new
+            IllegalArgumentException(Messages.getString("security.86", "cofactor")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public int getCofactor() {
+        return cofactor;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public EllipticCurve getCurve() {
+        return curve;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public ECPoint getGenerator() {
+        return generator;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getOrder() {
+        return order;
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/spec/ECPoint.java b/libcore/security/src/main/java/java/security/spec/ECPoint.java
new file mode 100644
index 0000000..b4c0737
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/ECPoint.java
@@ -0,0 +1,106 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+import java.math.BigInteger;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class ECPoint {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public static final ECPoint POINT_INFINITY = new ECPoint();
+    // affine X coordinate of this point
+    private final BigInteger affineX;
+    // affine Y coordinate of this point
+    private final BigInteger affineY;
+
+    // Private ctor for POINT_INFINITY
+    private ECPoint() {
+        affineX = null;
+        affineY = null;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public ECPoint(BigInteger affineX, BigInteger affineY) {
+        this.affineX = affineX;
+        if (this.affineX == null) {
+            throw new NullPointerException(Messages.getString("security.83", "X")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        this.affineY = affineY;
+        if (this.affineY == null) {
+            throw new NullPointerException(Messages.getString("security.83", "Y")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getAffineX() {
+        return affineX;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getAffineY() {
+        return affineY;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+        if (other instanceof ECPoint) {
+            if (this.affineX != null) {
+                ECPoint otherPoint = (ECPoint)other;
+                // no need to check for null in this case
+                return this.affineX.equals(otherPoint.affineX) &&
+                       this.affineY.equals(otherPoint.affineY);
+            } else {
+                return other == POINT_INFINITY;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public int hashCode() {
+        if (this.affineX != null) {
+            return affineX.hashCode() * 31 + affineY.hashCode();
+        }
+        return 11;
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/spec/ECPrivateKeySpec.java b/libcore/security/src/main/java/java/security/spec/ECPrivateKeySpec.java
new file mode 100644
index 0000000..3422f16
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/ECPrivateKeySpec.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+import java.math.BigInteger;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class ECPrivateKeySpec implements KeySpec {
+    // Private value associated with this key
+    private final BigInteger s;
+    // Elliptic Curve domain parameters associated with this key
+    private final ECParameterSpec params;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public ECPrivateKeySpec(BigInteger s, ECParameterSpec params) {
+        this.s = s;
+        this.params = params;
+        // throw NullPointerException if s or params is null
+        if (this.s == null) {
+            throw new NullPointerException(Messages.getString("security.83", "s")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if (this.params == null) {
+            throw new NullPointerException(Messages.getString("security.83", "params")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public ECParameterSpec getParams() {
+        return params;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getS() {
+        return s;
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/spec/ECPublicKeySpec.java b/libcore/security/src/main/java/java/security/spec/ECPublicKeySpec.java
new file mode 100644
index 0000000..3c41f8e
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/ECPublicKeySpec.java
@@ -0,0 +1,70 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class ECPublicKeySpec implements KeySpec {
+    // The public point
+    private final ECPoint w;
+    // The associated elliptic curve domain parameters
+    private final ECParameterSpec params;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public ECPublicKeySpec(ECPoint w, ECParameterSpec params) {
+        this.w = w;
+        this.params = params;
+        // throw NullPointerException if w or params is null
+        if (this.w == null) {
+            throw new NullPointerException(Messages.getString("security.83", "w")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if (this.params == null) {
+            throw new NullPointerException(Messages.getString("security.83", "params")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        // throw IllegalArgumentException if w is point at infinity
+        if (this.w.equals(ECPoint.POINT_INFINITY)) {
+            throw new IllegalArgumentException(
+                Messages.getString("security.84")); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public ECParameterSpec getParams() {
+        return params;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public ECPoint getW() {
+        return w;
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/spec/EllipticCurve.java b/libcore/security/src/main/java/java/security/spec/EllipticCurve.java
new file mode 100644
index 0000000..db1bacc
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/EllipticCurve.java
@@ -0,0 +1,176 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class EllipticCurve {
+
+    // Underlying finite field
+    private final ECField field;
+
+    // The first coefficient of the equation defining this elliptic curve
+    private final BigInteger a;
+
+    // The second coefficient of the equation defining this elliptic curve
+    private final BigInteger b;
+
+    // Bytes used during this elliptic curve generation,
+    // if it was generated randomly
+    private final byte[] seed;
+
+    // Hash code
+    private volatile int hash;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public EllipticCurve(ECField field, BigInteger a, BigInteger b, byte[] seed) {
+        this.field = field;
+        if (this.field == null) {
+            throw new NullPointerException(Messages.getString("security.7A")); //$NON-NLS-1$
+        }
+        this.a = a;
+        if (this.a == null) {
+            throw new NullPointerException(Messages.getString("security.7B")); //$NON-NLS-1$
+        }
+        this.b = b;
+        if (this.b == null) {
+            throw new NullPointerException(Messages.getString("security.7C")); //$NON-NLS-1$
+        }
+        // make defensive copy
+        if (seed == null) {
+            this.seed = null;
+        } else {
+            this.seed = new byte[seed.length];
+            System.arraycopy(seed, 0, this.seed, 0, this.seed.length);
+        }
+        // check parameters for ECFieldFp and ECFieldF2m.
+        // Check invariant: a and b must be in the field.
+        // Check conditions for custom ECField are not specified.
+        if (this.field instanceof ECFieldFp) {
+            BigInteger p = ((ECFieldFp) this.field).getP();
+            if (this.a.signum() < 0 || this.a.compareTo(p) >= 0) {
+                throw new IllegalArgumentException(Messages.getString("security.7D")); //$NON-NLS-1$
+            }
+            if (this.b.signum() < 0 || this.b.compareTo(p) >= 0) {
+                throw new IllegalArgumentException(Messages.getString("security.7E")); //$NON-NLS-1$
+            }
+        } else if (this.field instanceof ECFieldF2m) {
+            int fieldSizeInBits = this.field.getFieldSize();
+            if (!(this.a.bitLength() <= fieldSizeInBits)) {
+                throw new IllegalArgumentException(Messages.getString("security.7D")); //$NON-NLS-1$
+            }
+            if (!(this.b.bitLength() <= fieldSizeInBits)) {
+                throw new IllegalArgumentException(Messages.getString("security.7E")); //$NON-NLS-1$
+            }
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public EllipticCurve(ECField field, BigInteger a, BigInteger b) {
+        this(field, a, b, null);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getA() {
+        return a;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getB() {
+        return b;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public ECField getField() {
+        return field;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public byte[] getSeed() {
+        if (seed == null) {
+            return null;
+        } else {
+            // return copy
+            byte[] ret = new byte[seed.length];
+            System.arraycopy(seed, 0, ret, 0, ret.length);
+            return ret;
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+        if (!(other instanceof EllipticCurve)) {
+            return false;
+        }
+        EllipticCurve otherEc = (EllipticCurve) other;
+        return this.field.equals(otherEc.field) && this.a.equals(otherEc.a)
+                && this.b.equals(otherEc.b)
+                && Arrays.equals(this.seed, otherEc.seed);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public int hashCode() {
+        // hash init is delayed
+        if (hash == 0) {
+            int hash0 = 11;
+            hash0 = hash0 * 31 + field.hashCode();
+            hash0 = hash0 * 31 + a.hashCode();
+            hash0 = hash0 * 31 + b.hashCode();
+            if (seed != null) {
+                for (int i = 0; i < seed.length; i++) {
+                    hash0 = hash0 * 31 + seed[i];
+                }
+            } else {
+                hash0 = hash0 * 31;
+            }
+            hash = hash0;
+        }
+        return hash;
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/spec/EncodedKeySpec.java b/libcore/security/src/main/java/java/security/spec/EncodedKeySpec.java
new file mode 100644
index 0000000..f8f3162
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/EncodedKeySpec.java
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public abstract class EncodedKeySpec implements KeySpec {
+    // Encoded key
+    private final byte[] encodedKey;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public EncodedKeySpec(byte[] encodedKey) {
+        // Defensively copies parameter
+        // to prevent subsequent modification
+        this.encodedKey = new byte[encodedKey.length];
+        System.arraycopy(encodedKey, 0,
+                this.encodedKey, 0, this.encodedKey.length);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public byte[] getEncoded() {
+        // Defensively copies private array
+        // to prevent subsequent modification
+        byte[] ret = new byte[encodedKey.length];
+        System.arraycopy(encodedKey, 0, ret, 0, ret.length);
+        return ret;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract String getFormat();
+}
diff --git a/libcore/security/src/main/java/java/security/spec/InvalidKeySpecException.java b/libcore/security/src/main/java/java/security/spec/InvalidKeySpecException.java
new file mode 100644
index 0000000..6df9e5c
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/InvalidKeySpecException.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class InvalidKeySpecException extends GeneralSecurityException {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    private static final long serialVersionUID = 3546139293998810778L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public InvalidKeySpecException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public InvalidKeySpecException() {
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public InvalidKeySpecException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public InvalidKeySpecException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/spec/InvalidParameterSpecException.java b/libcore/security/src/main/java/java/security/spec/InvalidParameterSpecException.java
new file mode 100644
index 0000000..c7ce23f
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/InvalidParameterSpecException.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class InvalidParameterSpecException extends GeneralSecurityException {
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    private static final long serialVersionUID = -970468769593399342L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public InvalidParameterSpecException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public InvalidParameterSpecException() {
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/spec/KeySpec.java b/libcore/security/src/main/java/java/security/spec/KeySpec.java
new file mode 100644
index 0000000..908e154
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/KeySpec.java
@@ -0,0 +1,30 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public interface KeySpec {
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/java/security/spec/MGF1ParameterSpec.java b/libcore/security/src/main/java/java/security/spec/MGF1ParameterSpec.java
new file mode 100644
index 0000000..3bf2a0b
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/MGF1ParameterSpec.java
@@ -0,0 +1,72 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class MGF1ParameterSpec implements AlgorithmParameterSpec {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public static final MGF1ParameterSpec SHA1 =
+        new MGF1ParameterSpec("SHA-1"); //$NON-NLS-1$
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public static final MGF1ParameterSpec SHA256 =
+        new MGF1ParameterSpec("SHA-256"); //$NON-NLS-1$
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public static final MGF1ParameterSpec SHA384 =
+        new MGF1ParameterSpec("SHA-384"); //$NON-NLS-1$
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public static final MGF1ParameterSpec SHA512 =
+        new MGF1ParameterSpec("SHA-512"); //$NON-NLS-1$
+
+    //  Message digest algorithm name
+    private final String mdName;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public MGF1ParameterSpec(String mdName) {
+        this.mdName = mdName;
+        if (this.mdName == null) {
+            throw new NullPointerException(Messages.getString("security.80")); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public String getDigestAlgorithm() {
+        return mdName;
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/spec/PKCS8EncodedKeySpec.java b/libcore/security/src/main/java/java/security/spec/PKCS8EncodedKeySpec.java
new file mode 100644
index 0000000..070552f
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/PKCS8EncodedKeySpec.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class PKCS8EncodedKeySpec extends EncodedKeySpec {    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public PKCS8EncodedKeySpec(byte[] encodedKey) {
+        // Super class' ctor makes defensive parameter copy
+        super(encodedKey);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public byte[] getEncoded() {
+        // Super class' getEncoded() always returns a new array
+        return super.getEncoded();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public final String getFormat() {
+        return "PKCS#8"; //$NON-NLS-1$
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/spec/PSSParameterSpec.java b/libcore/security/src/main/java/java/security/spec/PSSParameterSpec.java
new file mode 100644
index 0000000..41428d1
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/PSSParameterSpec.java
@@ -0,0 +1,121 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class PSSParameterSpec implements AlgorithmParameterSpec {   
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public static final PSSParameterSpec DEFAULT = new PSSParameterSpec(20);
+
+    // Message digest algorithm name
+    private final String mdName;
+    // Mask generation function algorithm name
+    private final String mgfName;
+    // Mask generation function parameters
+    private final AlgorithmParameterSpec mgfSpec;
+    // Trailer field value
+    private final int trailerField;
+    // Salt length in bits
+    private final int saltLen;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public PSSParameterSpec(int saltLen) {
+        if (saltLen < 0) {
+            throw new IllegalArgumentException(Messages.getString("security.7F")); //$NON-NLS-1$
+        }
+        this.saltLen = saltLen;
+        this.mdName = "SHA-1"; //$NON-NLS-1$
+        this.mgfName = "MGF1"; //$NON-NLS-1$
+        this.mgfSpec = MGF1ParameterSpec.SHA1;
+        this.trailerField = 1;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref     * 
+     */
+    public PSSParameterSpec(String mdName, String mgfName,
+            AlgorithmParameterSpec mgfSpec, int saltLen, int trailerField) {
+
+        if (mdName == null) {
+            throw new NullPointerException(Messages.getString("security.80")); //$NON-NLS-1$
+        }
+        if (mgfName == null) {
+            throw new NullPointerException(Messages.getString("security.81")); //$NON-NLS-1$
+        }
+        if (saltLen < 0) {
+            throw new IllegalArgumentException(Messages.getString("security.7F")); //$NON-NLS-1$
+        }
+        if (trailerField < 0) {
+            throw new IllegalArgumentException(Messages.getString("security.82")); //$NON-NLS-1$
+        }
+        this.mdName = mdName;
+        this.mgfName = mgfName;
+        this.mgfSpec = mgfSpec;
+        this.saltLen = saltLen;
+        this.trailerField = trailerField;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public int getSaltLength() {
+        return saltLen;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public String getDigestAlgorithm() {
+        return mdName;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public String getMGFAlgorithm() {
+        return mgfName;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public AlgorithmParameterSpec getMGFParameters() {
+        return mgfSpec;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public int getTrailerField() {
+        return trailerField;
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/spec/RSAKeyGenParameterSpec.java b/libcore/security/src/main/java/java/security/spec/RSAKeyGenParameterSpec.java
new file mode 100644
index 0000000..9b03fcc
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/RSAKeyGenParameterSpec.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+import java.math.BigInteger;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class RSAKeyGenParameterSpec implements AlgorithmParameterSpec {    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public static final BigInteger F0 = BigInteger.valueOf(3L);
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public static final BigInteger F4 = BigInteger.valueOf(65537L);
+
+    // Key size
+    private final int keysize;
+    // Public Exponent
+    private final BigInteger publicExponent;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public RSAKeyGenParameterSpec(int keysize, BigInteger publicExponent) {
+        this.keysize = keysize;
+        this.publicExponent = publicExponent;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public int getKeysize() {
+        return keysize;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getPublicExponent() {
+        return publicExponent;
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java b/libcore/security/src/main/java/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java
new file mode 100644
index 0000000..8db2876
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java
@@ -0,0 +1,167 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+import java.math.BigInteger;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class RSAMultiPrimePrivateCrtKeySpec extends RSAPrivateKeySpec {
+    // Public Exponent
+    private final BigInteger publicExponent;
+    // Prime P
+    private final BigInteger primeP;
+    // Prime Q
+    private final BigInteger primeQ;
+    // Prime Exponent P
+    private final BigInteger primeExponentP;
+    // Prime Exponent Q
+    private final BigInteger primeExponentQ;
+    // CRT Coefficient
+    private final BigInteger crtCoefficient;
+    // Other Prime Info
+    private final RSAOtherPrimeInfo[] otherPrimeInfo;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public RSAMultiPrimePrivateCrtKeySpec(
+            BigInteger modulus,
+            BigInteger publicExponent,
+            BigInteger privateExponent,
+            BigInteger primeP,
+            BigInteger primeQ,
+            BigInteger primeExponentP,
+            BigInteger primeExponentQ,
+            BigInteger crtCoefficient,
+            RSAOtherPrimeInfo[] otherPrimeInfo) {
+
+        super(modulus, privateExponent);
+
+        // Perform checks specified
+        if (modulus == null) {
+            throw new NullPointerException(Messages.getString("security.83", "modulus")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if (privateExponent == null) {
+            throw new NullPointerException(Messages.getString("security.83", "privateExponent")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if (publicExponent == null) {
+            throw new NullPointerException(Messages.getString("security.83", "publicExponent")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if (primeP == null) {
+            throw new NullPointerException(Messages.getString("security.83", "primeP")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if (primeQ == null) {
+            throw new NullPointerException(Messages.getString("security.83", "primeQ")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if (primeExponentP == null) {
+            throw new NullPointerException(Messages.getString("security.83", "primeExponentP")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if (primeExponentQ == null) {
+            throw new NullPointerException(Messages.getString("security.83", "primeExponentQ")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if (crtCoefficient == null) {
+            throw new NullPointerException(Messages.getString("security.83", "crtCoefficient")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        if (otherPrimeInfo != null) {
+            if (otherPrimeInfo.length == 0) {
+                throw new IllegalArgumentException(
+                Messages.getString("security.85")); //$NON-NLS-1$
+            }
+            // Clone array to prevent subsequent modification
+            this.otherPrimeInfo = new RSAOtherPrimeInfo[otherPrimeInfo.length];
+            System.arraycopy(otherPrimeInfo, 0,
+                    this.otherPrimeInfo, 0, this.otherPrimeInfo.length);
+        } else {
+            this.otherPrimeInfo = null;
+        }
+        this.publicExponent = publicExponent;
+        this.primeP = primeP;
+        this.primeQ = primeQ;
+        this.primeExponentP = primeExponentP;
+        this.primeExponentQ = primeExponentQ;
+        this.crtCoefficient = crtCoefficient;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getCrtCoefficient() {
+        return crtCoefficient;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public RSAOtherPrimeInfo[] getOtherPrimeInfo() {
+        // Clone array (if not null) to prevent subsequent modification
+        if (otherPrimeInfo == null) {
+            return null;
+        } else {
+            RSAOtherPrimeInfo[] ret =
+                new RSAOtherPrimeInfo[otherPrimeInfo.length];
+            System.arraycopy(otherPrimeInfo, 0, ret, 0, ret.length);
+            return ret;
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getPrimeExponentP() {
+        return primeExponentP;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getPrimeExponentQ() {
+        return primeExponentQ;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getPrimeP() {
+        return primeP;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getPrimeQ() {
+        return primeQ;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getPublicExponent() {
+        return publicExponent;
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/spec/RSAOtherPrimeInfo.java b/libcore/security/src/main/java/java/security/spec/RSAOtherPrimeInfo.java
new file mode 100644
index 0000000..14ce0f8
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/RSAOtherPrimeInfo.java
@@ -0,0 +1,80 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+import java.math.BigInteger;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class RSAOtherPrimeInfo {
+    // Prime
+    private final BigInteger prime;
+    // Prime Exponent
+    private final BigInteger primeExponent;
+    // CRT Coefficient
+    private final BigInteger crtCoefficient;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public RSAOtherPrimeInfo(BigInteger prime,
+            BigInteger primeExponent, BigInteger crtCoefficient) {
+        if (prime == null) {
+            throw new NullPointerException(Messages.getString("security.83", "prime")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if (primeExponent == null) {
+            throw new NullPointerException(Messages.getString("security.83", "primeExponent")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        if (crtCoefficient == null) {
+            throw new NullPointerException(Messages.getString("security.83", "crtCoefficient")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        this.prime = prime;
+        this.primeExponent = primeExponent;
+        this.crtCoefficient = crtCoefficient;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public final BigInteger getCrtCoefficient() {
+        return crtCoefficient;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public final BigInteger getPrime() {
+        return prime;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public final BigInteger getExponent() {
+        return primeExponent;
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/spec/RSAPrivateCrtKeySpec.java b/libcore/security/src/main/java/java/security/spec/RSAPrivateCrtKeySpec.java
new file mode 100644
index 0000000..5c0eae7
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/RSAPrivateCrtKeySpec.java
@@ -0,0 +1,108 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+import java.math.BigInteger;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class RSAPrivateCrtKeySpec extends RSAPrivateKeySpec {    
+    // Public Exponent
+    private final BigInteger publicExponent;
+    // Prime P
+    private final BigInteger primeP;
+    // Prime Q
+    private final BigInteger primeQ;
+    // Prime Exponent P
+    private final BigInteger primeExponentP;
+    // Prime Exponent Q
+    private final BigInteger primeExponentQ;
+    // CRT Coefficient
+    private final BigInteger crtCoefficient;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public RSAPrivateCrtKeySpec(BigInteger modulus,
+                                BigInteger publicExponent,
+                                BigInteger privateExponent,
+                                BigInteger primeP,
+                                BigInteger primeQ,
+                                BigInteger primeExponentP,
+                                BigInteger primeExponentQ,
+                                BigInteger crtCoefficient) {
+
+        super(modulus, privateExponent);
+
+        this.publicExponent = publicExponent;
+        this.primeP = primeP;
+        this.primeQ = primeQ;
+        this.primeExponentP = primeExponentP;
+        this.primeExponentQ = primeExponentQ;
+        this.crtCoefficient = crtCoefficient;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getCrtCoefficient() {
+        return crtCoefficient;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getPrimeExponentP() {
+        return primeExponentP;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getPrimeExponentQ() {
+        return primeExponentQ;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getPrimeP() {
+        return primeP;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getPrimeQ() {
+        return primeQ;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getPublicExponent() {
+        return publicExponent;
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/spec/RSAPrivateKeySpec.java b/libcore/security/src/main/java/java/security/spec/RSAPrivateKeySpec.java
new file mode 100644
index 0000000..355f2ba
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/RSAPrivateKeySpec.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+import java.math.BigInteger;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class RSAPrivateKeySpec implements KeySpec {    
+    // Modulus
+    private final BigInteger modulus;
+    // Private Exponent
+    private final BigInteger privateExponent;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public RSAPrivateKeySpec(BigInteger modulus, BigInteger privateExponent) {
+        this.modulus = modulus;
+        this.privateExponent = privateExponent;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getModulus() {
+        return modulus;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getPrivateExponent() {
+        return privateExponent;
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/spec/RSAPublicKeySpec.java b/libcore/security/src/main/java/java/security/spec/RSAPublicKeySpec.java
new file mode 100644
index 0000000..7bd64e6
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/RSAPublicKeySpec.java
@@ -0,0 +1,57 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+import java.math.BigInteger;
+
+/**
+ * @com.intel.drl.spec_ref
+ */
+public class RSAPublicKeySpec implements KeySpec {
+    // Modulus
+    private final BigInteger modulus;
+    // Public Exponent
+    private final BigInteger publicExponent;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public RSAPublicKeySpec(BigInteger modulus, BigInteger publicExponent) {
+        this.modulus = modulus;
+        this.publicExponent = publicExponent;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getModulus() {
+        return modulus;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public BigInteger getPublicExponent() {
+        return publicExponent;
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/spec/X509EncodedKeySpec.java b/libcore/security/src/main/java/java/security/spec/X509EncodedKeySpec.java
new file mode 100644
index 0000000..46e833e
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/X509EncodedKeySpec.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package java.security.spec;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class X509EncodedKeySpec extends EncodedKeySpec {
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public X509EncodedKeySpec(byte[] encodedKey) {
+        // Super class' ctor makes defensive parameter copy
+        super(encodedKey);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public byte[] getEncoded() {
+        // Super class' getEncoded() always returns a new array
+        return super.getEncoded();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public final String getFormat() {
+        return "X.509"; //$NON-NLS-1$
+    }
+}
diff --git a/libcore/security/src/main/java/java/security/spec/package.html b/libcore/security/src/main/java/java/security/spec/package.html
new file mode 100644
index 0000000..0d4b963
--- /dev/null
+++ b/libcore/security/src/main/java/java/security/spec/package.html
@@ -0,0 +1,18 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
+</head>
+<html>
+<body>
+<p>
+This package provides the classes and interfaces needed to specify keys and parameter for
+encryption and signing algorithms. Following standards are supported:
+(1) PKCS#1 RSA encryption standard;
+(2) FIPS-186 DSA (signature) standard;
+(3) PKCS#8 private key information standard.
+Keys may be specified via algorithm or in a more abstract and general way with ASN.1.
+The parameters for the Elliptic Curve (EC)  encryption algorithm are only specified as
+input parameters to the relevant EC-generator.
+</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/libcore/security/src/main/java/javax/security/cert/Certificate.java b/libcore/security/src/main/java/javax/security/cert/Certificate.java
new file mode 100644
index 0000000..d94427d
--- /dev/null
+++ b/libcore/security/src/main/java/javax/security/cert/Certificate.java
@@ -0,0 +1,109 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package javax.security.cert;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.util.Arrays;
+import javax.security.cert.CertificateEncodingException;
+import javax.security.cert.CertificateException;
+
+/**
+ * @com.intel.drl.spec_ref
+ */
+public abstract class Certificate {
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public Certificate() {}
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (!(obj instanceof Certificate)) {
+            return false;
+        }
+        Certificate object = (Certificate) obj;
+        try {
+            return Arrays.equals(getEncoded(), object.getEncoded());
+        } catch (CertificateEncodingException e) {
+            return false;
+        }
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public int hashCode() {
+        int res = 0;
+        try {
+            byte[] array = getEncoded();
+            for (int i=0; i<array.length; i++) {
+                res += array[i];
+            }
+        } catch (CertificateEncodingException e) {
+        }
+        return res;
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract byte[] getEncoded()
+            throws CertificateEncodingException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract void verify(PublicKey key)
+            throws CertificateException, NoSuchAlgorithmException,
+                   InvalidKeyException, NoSuchProviderException,
+                   SignatureException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract void verify(PublicKey key, String sigProvider)
+            throws CertificateException, NoSuchAlgorithmException, 
+                   InvalidKeyException, NoSuchProviderException,
+                   SignatureException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract String toString();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract PublicKey getPublicKey();
+}
+
diff --git a/libcore/security/src/main/java/javax/security/cert/CertificateEncodingException.java b/libcore/security/src/main/java/javax/security/cert/CertificateEncodingException.java
new file mode 100644
index 0000000..a567f75
--- /dev/null
+++ b/libcore/security/src/main/java/javax/security/cert/CertificateEncodingException.java
@@ -0,0 +1,51 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package javax.security.cert;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+
+public class CertificateEncodingException extends CertificateException {
+
+    /**
+     * @serial
+     */
+    private static final long serialVersionUID = -8187642723048403470L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public CertificateEncodingException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public CertificateEncodingException() {
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/javax/security/cert/CertificateException.java b/libcore/security/src/main/java/javax/security/cert/CertificateException.java
new file mode 100644
index 0000000..aedb285
--- /dev/null
+++ b/libcore/security/src/main/java/javax/security/cert/CertificateException.java
@@ -0,0 +1,50 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package javax.security.cert;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class CertificateException extends Exception {
+
+    /**
+     * @serial
+     */
+    private static final long serialVersionUID = -5757213374030785290L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public CertificateException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public CertificateException() {
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/javax/security/cert/CertificateExpiredException.java b/libcore/security/src/main/java/javax/security/cert/CertificateExpiredException.java
new file mode 100644
index 0000000..87366ae
--- /dev/null
+++ b/libcore/security/src/main/java/javax/security/cert/CertificateExpiredException.java
@@ -0,0 +1,50 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package javax.security.cert;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class CertificateExpiredException extends CertificateException {
+
+    /**
+     * @serial
+     */
+    private static final long serialVersionUID = 5091601212177261883L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public CertificateExpiredException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public CertificateExpiredException() {
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/javax/security/cert/CertificateNotYetValidException.java b/libcore/security/src/main/java/javax/security/cert/CertificateNotYetValidException.java
new file mode 100644
index 0000000..cdaccce
--- /dev/null
+++ b/libcore/security/src/main/java/javax/security/cert/CertificateNotYetValidException.java
@@ -0,0 +1,50 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package javax.security.cert;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class CertificateNotYetValidException extends CertificateException {
+
+    /**
+     * @serial
+     */
+    private static final long serialVersionUID = -8976172474266822818L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public CertificateNotYetValidException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public CertificateNotYetValidException() {
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/javax/security/cert/CertificateParsingException.java b/libcore/security/src/main/java/javax/security/cert/CertificateParsingException.java
new file mode 100644
index 0000000..60c4ba0
--- /dev/null
+++ b/libcore/security/src/main/java/javax/security/cert/CertificateParsingException.java
@@ -0,0 +1,50 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package javax.security.cert;
+
+/**
+ * @com.intel.drl.spec_ref
+ * 
+ */
+public class CertificateParsingException extends CertificateException {
+
+    /**
+     * @serial
+     */
+    private static final long serialVersionUID = -8449352422951136229L;
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public CertificateParsingException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     *  
+     */
+    public CertificateParsingException() {
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/javax/security/cert/X509Certificate.java b/libcore/security/src/main/java/javax/security/cert/X509Certificate.java
new file mode 100644
index 0000000..1ead4ac
--- /dev/null
+++ b/libcore/security/src/main/java/javax/security/cert/X509Certificate.java
@@ -0,0 +1,273 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package javax.security.cert;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.math.BigInteger;
+import java.security.AccessController;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.SignatureException;
+import java.security.cert.CertificateFactory;
+import java.util.Date;
+import javax.security.cert.Certificate;
+import javax.security.cert.CertificateEncodingException;
+import javax.security.cert.CertificateException;
+import javax.security.cert.CertificateExpiredException;
+import javax.security.cert.CertificateNotYetValidException;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @com.intel.drl.spec_ref
+ */
+public abstract class X509Certificate extends Certificate {
+
+    private static Constructor constructor;
+    
+    static {
+        try {
+            String classname = (String) AccessController.doPrivileged(
+                new java.security.PrivilegedAction() {
+                    public Object run() {
+                        return Security.getProperty("cert.provider.x509v1"); //$NON-NLS-1$
+                    }
+                }
+            );
+            Class cl = Class.forName(classname);
+            constructor =
+                cl.getConstructor(new Class[] {InputStream.class});
+        } catch (Throwable e) {
+        }
+    }
+    
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public X509Certificate() {
+        super();
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public static final X509Certificate getInstance(InputStream inStream)
+                                             throws CertificateException {
+        if (inStream == null) {
+            throw new CertificateException(Messages.getString("security.87")); //$NON-NLS-1$
+        }
+        if (constructor != null) {
+            try {
+                return (X509Certificate) 
+                    constructor.newInstance(new Object[] {inStream});
+            } catch (Throwable e) {
+                throw new CertificateException(e.getMessage());
+            }
+        }
+
+        final java.security.cert.X509Certificate cert;
+        try {
+            CertificateFactory cf = CertificateFactory.getInstance("X.509"); //$NON-NLS-1$
+            cert = (java.security.cert.X509Certificate)
+                                            cf.generateCertificate(inStream);
+        } catch (java.security.cert.CertificateException e) {
+            throw new CertificateException(e.getMessage());
+        }
+
+        return new X509Certificate() {
+
+            public byte[] getEncoded() throws CertificateEncodingException {
+                try {
+                    return cert.getEncoded();
+                } catch (java.security.cert.CertificateEncodingException e) {
+                    throw new CertificateEncodingException(e.getMessage());
+                }
+            }
+
+            public void verify(PublicKey key) throws CertificateException,
+                                NoSuchAlgorithmException, InvalidKeyException,
+                                NoSuchProviderException, SignatureException {
+                try {
+                    cert.verify(key);
+                } catch (java.security.cert.CertificateException e) {
+                    throw new CertificateException(e.getMessage());
+                }
+            }
+
+            public void verify(PublicKey key, String sigProvider)
+                            throws CertificateException,
+                                NoSuchAlgorithmException, InvalidKeyException,
+                                NoSuchProviderException, SignatureException {
+                try {
+                    cert.verify(key, sigProvider);
+                } catch (java.security.cert.CertificateException e) {
+                    throw new CertificateException(e.getMessage());
+                }
+            }
+
+            public String toString() {
+                return cert.toString();
+            }
+
+            public PublicKey getPublicKey() {
+                return cert.getPublicKey();
+            }
+
+            public void checkValidity() throws CertificateExpiredException,
+                                   CertificateNotYetValidException {
+                try {
+                    cert.checkValidity();
+                } catch (java.security.cert.CertificateNotYetValidException e) {
+                    throw new CertificateNotYetValidException(e.getMessage());
+                } catch (java.security.cert.CertificateExpiredException e) {
+                    throw new CertificateExpiredException(e.getMessage());
+                }
+            }
+
+            public void checkValidity(Date date) 
+                            throws CertificateExpiredException,
+                                   CertificateNotYetValidException {
+                try {
+                    cert.checkValidity(date);
+                } catch (java.security.cert.CertificateNotYetValidException e) {
+                    throw new CertificateNotYetValidException(e.getMessage());
+                } catch (java.security.cert.CertificateExpiredException e) {
+                    throw new CertificateExpiredException(e.getMessage());
+                }
+            }
+
+            public int getVersion() {
+                return 2;
+            }
+
+            public BigInteger getSerialNumber() {
+                return cert.getSerialNumber();
+            }
+
+            public Principal getIssuerDN() {
+                return cert.getIssuerDN();
+            }
+
+            public Principal getSubjectDN() {
+                return cert.getSubjectDN();
+            }
+
+            public Date getNotBefore() {
+                return cert.getNotBefore();
+            }
+
+            public Date getNotAfter() {
+                return cert.getNotAfter();
+            }
+
+            public String getSigAlgName() {
+                return cert.getSigAlgName();
+            }
+
+            public String getSigAlgOID() {
+                return cert.getSigAlgOID();
+            }
+
+            public byte[] getSigAlgParams() {
+                return cert.getSigAlgParams();
+            }
+        };
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public static final X509Certificate getInstance(byte[] certData)
+                                             throws CertificateException {
+        if (certData == null) {
+            throw new CertificateException(Messages.getString("security.88")); //$NON-NLS-1$
+        }
+        ByteArrayInputStream bais = new ByteArrayInputStream(certData);
+        return getInstance(bais);
+    }
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract void checkValidity()
+            throws CertificateExpiredException, CertificateNotYetValidException;
+
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract void checkValidity(Date date)
+            throws CertificateExpiredException, CertificateNotYetValidException;
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract int getVersion();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract BigInteger getSerialNumber();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract Principal getIssuerDN();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract Principal getSubjectDN();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract Date getNotBefore();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract Date getNotAfter();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract String getSigAlgName();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract String getSigAlgOID();
+
+    /**
+     * @com.intel.drl.spec_ref
+     */
+    public abstract byte[] getSigAlgParams();
+}
+
diff --git a/libcore/security/src/main/java/javax/security/cert/package.html b/libcore/security/src/main/java/javax/security/cert/package.html
new file mode 100644
index 0000000..60b9095
--- /dev/null
+++ b/libcore/security/src/main/java/javax/security/cert/package.html
@@ -0,0 +1,14 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
+</head>
+<html>
+<body>
+<p>
+This package is provided only for compatibility reasons. It contains  a simplified
+version of the java.security.cert package that was previously used by JSSE (Java SSL  package).
+All applications that do not have to be compatible with older versions of JSSE (that is
+before Java SDK 1.5) should only use java.security.cert.
+</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/DefaultPolicyScanner.java b/libcore/security/src/main/java/org/apache/harmony/security/DefaultPolicyScanner.java
new file mode 100644
index 0000000..ba3229b
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/DefaultPolicyScanner.java
@@ -0,0 +1,520 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StreamTokenizer;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * This is a basic high-level tokenizer of policy files. It takes in a stream,
+ * analyzes data read from it and returns a set of structured tokens. <br>
+ * This implementation recognizes text files, consisting of clauses with the
+ * following syntax:
+ * 
+ * <pre>
+ * 
+ *     keystore &quot;some_keystore_url&quot;, &quot;keystore_type&quot;;
+ *  
+ * </pre>
+ * <pre>
+ * 
+ *     grant [SignedBy &quot;signer_names&quot;] [, CodeBase &quot;URL&quot;]
+ *      [, Principal [principal_class_name] &quot;principal_name&quot;]
+ *      [, Principal [principal_class_name] &quot;principal_name&quot;] ... {
+ *      permission permission_class_name [ &quot;target_name&quot; ] [, &quot;action&quot;] 
+ *      [, SignedBy &quot;signer_names&quot;];
+ *      permission ...
+ *      };
+ *  
+ * </pre>
+ * 
+ * For semantical details of this format, see the
+ * {@link org.apache.harmony.security.fortress.DefaultPolicy default policy description}.
+ * <br>
+ * Keywords are case-insensitive in contrast to quoted string literals.
+ * Comma-separation rule is quite forgiving, most commas may be just omitted.
+ * Whitespaces, line- and block comments are ignored. Symbol-level tokenization
+ * is delegated to java.io.StreamTokenizer. <br>
+ * <br>
+ * This implementation is effectively thread-safe, as it has no field references
+ * to data being processed (that is, passes all the data as method parameters).
+ * 
+ * @see org.apache.harmony.security.fortress.DefaultPolicyParser
+ */
+public class DefaultPolicyScanner {
+
+    /**
+     * Specific exception class to signal policy file syntax error.
+     * 
+     */
+    public static class InvalidFormatException extends Exception {
+
+        /**
+         * @serial
+         */
+        private static final long serialVersionUID = 5789786270390222184L;
+
+        /** 
+         * Constructor with detailed message parameter. 
+         */
+        public InvalidFormatException(String arg0) {
+            super(arg0);
+        }
+    }
+
+    /**
+     * Configures passed tokenizer accordingly to supported syntax.
+     */
+    protected StreamTokenizer configure(StreamTokenizer st) {
+        st.slashSlashComments(true);
+        st.slashStarComments(true);
+        st.wordChars('_', '_');
+        st.wordChars('$', '$');
+        return st;
+    }
+
+    /**
+     * Performs the main parsing loop. Starts with creating and configuring a
+     * StreamTokenizer instance; then tries to recognize <i>keystore </i> or
+     * <i>grant </i> keyword. When found, invokes read method corresponding to
+     * the clause and collects result to the passed collection.
+     * 
+     * @param r
+     *            policy stream reader
+     * @param grantEntries
+     *            a collection to accumulate parsed GrantEntries
+     * @param keystoreEntries
+     *            a collection to accumulate parsed KeystoreEntries
+     * @throws IOException
+     *             if stream reading failed
+     * @throws InvalidFormatException
+     *             if unexpected or unknown token encountered
+     */
+    public void scanStream(Reader r, Collection<GrantEntry> grantEntries,
+            List<KeystoreEntry> keystoreEntries) throws IOException,
+            InvalidFormatException {
+        StreamTokenizer st = configure(new StreamTokenizer(r));
+        //main parsing loop
+        parsing: while (true) {
+            switch (st.nextToken()) {
+            case StreamTokenizer.TT_EOF: //we've done the job
+                break parsing;
+
+            case StreamTokenizer.TT_WORD:
+                if ("keystore".equalsIgnoreCase(st.sval)) { //$NON-NLS-1$
+                    keystoreEntries.add(readKeystoreEntry(st));
+                } else if ("grant".equalsIgnoreCase(st.sval)) { //$NON-NLS-1$
+                    grantEntries.add(readGrantEntry(st));
+                } else {
+                    handleUnexpectedToken(st, Messages.getString("security.89")); //$NON-NLS-1$
+                }
+                break;
+
+            case ';': //just delimiter of entries
+                break;
+
+            default:
+                handleUnexpectedToken(st);
+                break;
+            }
+        }
+    }
+
+    /**
+     * Tries to read <i>keystore </i> clause fields. The expected syntax is
+     * 
+     * <pre>
+     * 
+     *     &quot;some_keystore_url&quot;[, &quot;keystore_type&quot;];
+     *  
+     * </pre>
+     * 
+     * @return successfully parsed KeystoreEntry
+     * @throws IOException
+     *             if stream reading failed
+     * @throws InvalidFormatException
+     *             if unexpected or unknown token encountered
+     */
+    protected KeystoreEntry readKeystoreEntry(StreamTokenizer st)
+            throws IOException, InvalidFormatException {
+        KeystoreEntry ke = new KeystoreEntry();
+        if (st.nextToken() == '"') {
+            ke.url = st.sval;
+            if ((st.nextToken() == '"')
+                    || ((st.ttype == ',') && (st.nextToken() == '"'))) {
+                ke.type = st.sval;
+            } else { // handle token in the main loop
+                st.pushBack();
+            }
+        } else {
+            handleUnexpectedToken(st, Messages.getString("security.8A")); //$NON-NLS-1$
+        }
+        return ke;
+    }
+
+    /**
+     * Tries to read <i>grant </i> clause. <br>
+     * First, it reads <i>codebase </i>, <i>signedby </i>, <i>principal </i>
+     * entries till the '{' (opening curly brace) symbol. Then it calls
+     * readPermissionEntries() method to read the permissions of this clause.
+     * <br>
+     * Principal entries (if any) are read by invoking readPrincipalEntry()
+     * method, obtained PrincipalEntries are accumulated. <br>
+     * The expected syntax is
+     * 
+     * <pre>
+     * 
+     *     [ [codebase &quot;url&quot;] | [signedby &quot;name1,...,nameN&quot;] | 
+     *          principal ...] ]* { ... }
+     *  
+     * </pre>
+     * 
+     * @return successfully parsed GrantEntry
+     * @throws IOException
+     *             if stream reading failed
+     * @throws InvalidFormatException
+     *             if unexpected or unknown token encountered
+     */
+    protected GrantEntry readGrantEntry(StreamTokenizer st) throws IOException,
+            InvalidFormatException {
+        GrantEntry ge = new GrantEntry();
+        parsing: while (true) {
+            switch (st.nextToken()) {
+
+            case StreamTokenizer.TT_WORD:
+                if ("signedby".equalsIgnoreCase(st.sval)) { //$NON-NLS-1$
+                    if (st.nextToken() == '"') {
+                        ge.signers = st.sval;
+                    } else {
+                        handleUnexpectedToken(st, Messages.getString("security.8B")); //$NON-NLS-1$
+                    }
+                } else if ("codebase".equalsIgnoreCase(st.sval)) { //$NON-NLS-1$
+                    if (st.nextToken() == '"') {
+                        ge.codebase = st.sval;
+                    } else {
+                        handleUnexpectedToken(st, Messages.getString("security.8C")); //$NON-NLS-1$
+                    }
+                } else if ("principal".equalsIgnoreCase(st.sval)) { //$NON-NLS-1$
+                    ge.addPrincipal(readPrincipalEntry(st));
+                } else {
+                    handleUnexpectedToken(st);
+                }
+                break;
+
+            case ',': //just delimiter of entries
+                break;
+
+            case '{':
+                ge.permissions = readPermissionEntries(st);
+                break parsing;
+
+            default: // handle token in the main loop
+                st.pushBack();
+                break parsing;
+            }
+        }
+
+        return ge;
+    }
+
+    /**
+     * Tries to read <i>Principal </i> entry fields. The expected syntax is
+     * 
+     * <pre>
+     * 
+     *     [ principal_class_name ] &quot;principal_name&quot;
+     *  
+     * </pre>
+     * 
+     * Both class and name may be wildcards, wildcard names should not
+     * surrounded by quotes.
+     * 
+     * @return successfully parsed PrincipalEntry
+     * @throws IOException
+     *             if stream reading failed
+     * @throws InvalidFormatException
+     *             if unexpected or unknown token encountered
+     */
+    protected PrincipalEntry readPrincipalEntry(StreamTokenizer st)
+            throws IOException, InvalidFormatException {
+        PrincipalEntry pe = new PrincipalEntry();
+        if (st.nextToken() == StreamTokenizer.TT_WORD) {
+            pe.klass = st.sval;
+            st.nextToken();
+        } else if (st.ttype == '*') {
+            pe.klass = PrincipalEntry.WILDCARD;
+            st.nextToken();
+        }
+        if (st.ttype == '"') {
+            pe.name = st.sval;
+        } else if (st.ttype == '*') {
+            pe.name = PrincipalEntry.WILDCARD;
+        } else {
+            handleUnexpectedToken(st, Messages.getString("security.8D")); //$NON-NLS-1$
+        }
+        return pe;
+    }
+
+    /**
+     * Tries to read a list of <i>permission </i> entries. The expected syntax
+     * is
+     * 
+     * <pre>
+     * 
+     *     permission permission_class_name
+     *          [ &quot;target_name&quot; ] [, &quot;action_list&quot;]
+     *          [, signedby &quot;name1,name2,...&quot;];
+     *  
+     * </pre>
+     * 
+     * List is terminated by '}' (closing curly brace) symbol.
+     * 
+     * @return collection of successfully parsed PermissionEntries
+     * @throws IOException
+     *             if stream reading failed
+     * @throws InvalidFormatException
+     *             if unexpected or unknown token encountered
+     */
+    protected Collection<PermissionEntry> readPermissionEntries(
+            StreamTokenizer st) throws IOException, InvalidFormatException {
+        Collection<PermissionEntry> permissions = new HashSet<PermissionEntry>();
+        parsing: while (true) {
+            switch (st.nextToken()) {
+
+            case StreamTokenizer.TT_WORD:
+                if ("permission".equalsIgnoreCase(st.sval)) { //$NON-NLS-1$
+                    PermissionEntry pe = new PermissionEntry();
+                    if (st.nextToken() == StreamTokenizer.TT_WORD) {
+                        pe.klass = st.sval;
+                        if (st.nextToken() == '"') {
+                            pe.name = st.sval;
+                            st.nextToken();
+                        }
+                        if (st.ttype == ',') {
+                            st.nextToken();
+                        }
+                        if (st.ttype == '"') {
+                            pe.actions = st.sval;
+                            if (st.nextToken() == ',') {
+                                st.nextToken();
+                            }
+                        }
+                        if (st.ttype == StreamTokenizer.TT_WORD
+                                && "signedby".equalsIgnoreCase(st.sval)) { //$NON-NLS-1$
+                            if (st.nextToken() == '"') {
+                                pe.signers = st.sval;
+                            } else {
+                                handleUnexpectedToken(st);
+                            }
+                        } else { // handle token in the next iteration
+                            st.pushBack();
+                        }
+                        permissions.add(pe);
+                        continue parsing;
+                    }
+                }
+                handleUnexpectedToken(st, Messages.getString("security.8E")); //$NON-NLS-1$
+                break;
+
+            case ';': //just delimiter of entries
+                break;
+
+            case '}': //end of list
+                break parsing;
+
+            default: // invalid token
+                handleUnexpectedToken(st);
+                break;
+            }
+        }
+
+        return permissions;
+    }
+
+    /**
+     * Formats a detailed description of tokenizer status: current token,
+     * current line number, etc.
+     */
+    protected String composeStatus(StreamTokenizer st) {
+        return st.toString();
+    }
+
+    /**
+     * Throws InvalidFormatException with detailed diagnostics.
+     * 
+     * @param st
+     *            a tokenizer holding the erroneous token
+     * @param message
+     *            a user-friendly comment, probably explaining expected syntax.
+     *            Should not be <code>null</code>- use the overloaded
+     *            single-parameter method instead.
+     */
+    protected final void handleUnexpectedToken(StreamTokenizer st,
+            String message) throws InvalidFormatException {
+        throw new InvalidFormatException(Messages.getString("security.8F", //$NON-NLS-1$
+                composeStatus(st), message));
+    }
+
+    /**
+     * Throws InvalidFormatException with error status: which token is
+     * unexpected on which line.
+     * 
+     * @param st
+     *            a tokenizer holding the erroneous token
+     */
+    protected final void handleUnexpectedToken(StreamTokenizer st)
+            throws InvalidFormatException {
+        throw new InvalidFormatException(Messages.getString("security.90", //$NON-NLS-1$
+                composeStatus(st)));
+    }
+
+    /**
+     * Compound token representing <i>keystore </i> clause. See policy format
+     * {@link org.apache.harmony.security.fortress.DefaultPolicy description}for details.
+     * 
+     * @see org.apache.harmony.security.fortress.DefaultPolicyParser
+     * @see org.apache.harmony.security.DefaultPolicyScanner
+     */
+    public static class KeystoreEntry {
+
+        /**
+         * The URL part of keystore clause.
+         */
+        public String url;
+
+        /**
+         * The typename part of keystore clause.
+         */
+        public String type;
+    }
+
+    /**
+     * Compound token representing <i>grant </i> clause. See policy format
+     * {@link org.apache.harmony.security.fortress.DefaultPolicy description}for details.
+     * 
+     * @see org.apache.harmony.security.fortress.DefaultPolicyParser
+     * @see org.apache.harmony.security.DefaultPolicyScanner
+     */
+    public static class GrantEntry {
+
+        /**
+         * The signers part of grant clause. This is a comma-separated list of
+         * certificate aliases.
+         */
+        public String signers;
+
+        /**
+         * The codebase part of grant clause. This is an URL from which code
+         * originates.
+         */
+        public String codebase;
+
+        /**
+         * Collection of PrincipalEntries of grant clause.
+         */
+        public Collection<PrincipalEntry> principals;
+
+        /**
+         * Collection of PermissionEntries of grant clause.
+         */
+        public Collection<PermissionEntry> permissions;
+
+        /**
+         * Adds specified element to the <code>principals</code> collection.
+         * If collection does not exist yet, creates a new one.
+         */
+        public void addPrincipal(PrincipalEntry pe) {
+            if (principals == null) {
+                principals = new HashSet<PrincipalEntry>();
+            }
+            principals.add(pe);
+        }
+
+    }
+
+    /**
+     * Compound token representing <i>principal </i> entry of a <i>grant </i>
+     * clause. See policy format
+     * {@link org.apache.harmony.security.fortress.DefaultPolicy description}for details.
+     * 
+     * @see org.apache.harmony.security.fortress.DefaultPolicyParser
+     * @see org.apache.harmony.security.DefaultPolicyScanner
+     */
+    public static class PrincipalEntry {
+
+        /**
+         * Wildcard value denotes any class and/or any name.
+         * Must be asterisk, for proper general expansion and 
+         * PrivateCredentialsPermission wildcarding
+         */
+        public static final String WILDCARD = "*"; //$NON-NLS-1$
+        
+        /**
+         * The classname part of principal clause.
+         */
+        public String klass;
+
+        /**
+         * The name part of principal clause.
+         */
+        public String name;
+    }
+
+    /**
+     * Compound token representing <i>permission </i> entry of a <i>grant </i>
+     * clause. See policy format
+     * {@link org.apache.harmony.security.fortress.DefaultPolicy description}for details.
+     * 
+     * @see org.apache.harmony.security.fortress.DefaultPolicyParser
+     * @see org.apache.harmony.security.DefaultPolicyScanner
+     */
+    public static class PermissionEntry {
+
+        /**
+         * The classname part of permission clause.
+         */
+        public String klass;
+
+        /**
+         * The name part of permission clause.
+         */
+        public String name;
+
+        /**
+         * The actions part of permission clause.
+         */
+        public String actions;
+
+        /**
+         * The signers part of permission clause. This is a comma-separated list
+         * of certificate aliases.
+         */
+        public String signers;
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/PolicyEntry.java b/libcore/security/src/main/java/org/apache/harmony/security/PolicyEntry.java
new file mode 100644
index 0000000..4c7aa5b
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/PolicyEntry.java
@@ -0,0 +1,97 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security;
+
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.Principal;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.apache.harmony.security.fortress.PolicyUtils;
+
+
+/**
+ * This class represents an elementary block of a security policy. It associates
+ * a CodeSource of an executable code, Principals allowed to execute the code,
+ * and a set of granted Permissions.
+ * 
+ * @see org.apache.harmony.security.fortress.DefaultPolicy
+ */
+public class PolicyEntry {
+
+    // Store CodeSource
+    private final CodeSource cs;
+
+    // Array of principals 
+    private final Principal[] principals;
+
+    // Permissions collection
+    private final Collection<Permission> permissions;
+
+    /**
+     * Constructor with initialization parameters. Passed collections are not
+     * referenced directly, but copied.
+     */
+    public PolicyEntry(CodeSource cs, Collection<? extends Principal> prs,
+            Collection<? extends Permission> permissions) {
+        this.cs = cs;
+        this.principals = (prs == null || prs.isEmpty()) ? null
+                : (Principal[]) prs.toArray(new Principal[prs.size()]);
+        this.permissions = (permissions == null || permissions.isEmpty()) ? null
+                : Collections.unmodifiableCollection(permissions);
+    }
+
+    /**
+     * Checks if passed CodeSource matches this PolicyEntry. Null CodeSource of
+     * PolicyEntry implies any CodeSource; non-null CodeSource forwards to its
+     * imply() method.
+     */
+    public boolean impliesCodeSource(CodeSource codeSource) {
+        return (cs == null) ? true : cs.implies(codeSource);
+    }
+
+    /**
+     * Checks if specified Principals match this PolicyEntry. Null or empty set
+     * of Principals of PolicyEntry implies any Principals; otherwise specified
+     * array must contain all Principals of this PolicyEntry.
+     */
+    public boolean impliesPrincipals(Principal[] prs) {
+        return PolicyUtils.matchSubset(principals, prs);
+    }
+
+    /**
+     * Returns unmodifiable collection of permissions defined by this
+     * PolicyEntry, may be <code>null</code>.
+     */
+    public Collection<Permission> getPermissions() {
+        return permissions;
+    }
+
+    /**
+     * Returns true if this PolicyEntry defines no Permissions, false otherwise.
+     */
+    public boolean isVoid() {
+        return permissions == null || permissions.size() == 0;
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/PrivateKeyImpl.java b/libcore/security/src/main/java/org/apache/harmony/security/PrivateKeyImpl.java
new file mode 100644
index 0000000..a04ced0
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/PrivateKeyImpl.java
@@ -0,0 +1,66 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+
+package org.apache.harmony.security;
+
+import java.security.PrivateKey;
+
+/**
+ * PrivateKeyImpl
+ */
+public class PrivateKeyImpl implements PrivateKey {
+
+    /*
+     * @serial
+     */
+    private static final long serialVersionUID = 7776497482533790279L;
+
+    private String algorithm;
+
+    private byte[] encoding;
+
+    public PrivateKeyImpl(String algorithm) {
+        this.algorithm = algorithm;
+    }
+
+    public String getAlgorithm() {
+        return algorithm;
+    }
+
+    public String getFormat() {
+        return "PKCS#8"; //$NON-NLS-1$
+    }
+
+    public byte[] getEncoded() {
+
+        byte[] toReturn = new byte[encoding.length];
+        System.arraycopy(encoding, 0, toReturn, 0, encoding.length);
+
+        return toReturn;
+    }
+
+    public void setAlgorithm(String algorithm) {
+        this.algorithm = algorithm;
+    }
+
+    public void setEncoding(byte[] encoding) {
+        this.encoding = new byte[encoding.length];
+        System.arraycopy(encoding, 0, this.encoding, 0, encoding.length);
+    }
+
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/PublicKeyImpl.java b/libcore/security/src/main/java/org/apache/harmony/security/PublicKeyImpl.java
new file mode 100644
index 0000000..15196ae
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/PublicKeyImpl.java
@@ -0,0 +1,72 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+
+package org.apache.harmony.security;
+
+import java.security.PublicKey;
+
+
+/**
+ * PublicKeyImpl
+ */
+public class PublicKeyImpl implements PublicKey {
+    
+    /**
+     * @serial
+     */
+    private static final long serialVersionUID = 7179022516819534075L;
+
+
+    private byte[] encoding;
+
+    private String algorithm;
+
+
+    public PublicKeyImpl(String algorithm) { 
+        this.algorithm = algorithm;
+    }
+
+
+    public String getAlgorithm() {
+        return algorithm;
+    }
+
+
+    public String getFormat() {
+        return "X.509"; //$NON-NLS-1$
+    }
+
+
+    public byte[] getEncoded() {
+        byte[] result = new byte[encoding.length];
+        System.arraycopy(encoding, 0, result, 0, encoding.length);
+        return result;
+    }
+
+
+    public void setAlgorithm(String algorithm) {
+        this.algorithm = algorithm;
+    }
+
+
+    public void setEncoding(byte[] encoding) {
+        this.encoding = new byte[encoding.length];
+        System.arraycopy(encoding, 0, this.encoding, 0, encoding.length);
+    }
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/SystemScope.java b/libcore/security/src/main/java/org/apache/harmony/security/SystemScope.java
new file mode 100644
index 0000000..7acfe15
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/SystemScope.java
@@ -0,0 +1,162 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Aleksei Y. Semenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security;
+
+import java.security.Identity;
+import java.security.IdentityScope;
+import java.security.KeyManagementException;
+import java.security.PublicKey;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * @see java.security.IdentityScope
+ */
+
+public class SystemScope extends IdentityScope {
+
+    /**
+     * @serial
+     */
+    private static final long serialVersionUID = -4810285697932522607L;
+
+    // Identities hash: key is the identity name
+    private Hashtable names = new Hashtable();
+
+    // Identities hash: key is the public key
+    private Hashtable keys = new Hashtable();
+
+    /**
+     * @see java.security.IdentityScope#IdentityScope()
+     */
+    public SystemScope() {
+        super();
+    }
+
+    /**
+     * @see java.security.IdentityScope#IdentityScope(String)
+     */
+    public SystemScope(String name) {
+        super(name);
+    }
+
+    /**
+     * @see java.security.IdentityScope#IdentityScope(String, IdentityScope)
+     */
+    public SystemScope(String name, IdentityScope scope)
+            throws KeyManagementException {
+        super(name, scope);
+    }
+
+    /**
+     * @see java.security.IdentityScope#size()
+     */
+    public int size() {
+        return names.size();
+    }
+
+    /**
+     * @see java.security.IdentityScope#getIdentity(java.lang.String)
+     */
+    public synchronized Identity getIdentity(String name) {
+        if (name == null) {
+            throw new NullPointerException();
+        }
+        return (Identity) names.get(name);
+    }
+
+    /**
+     * @see java.security.IdentityScope#getIdentity(java.security.PublicKey)
+     */
+    public synchronized Identity getIdentity(PublicKey key) {
+        if (key == null) {
+            return null;
+        }
+        return (Identity) keys.get(key);
+    }
+
+    /**
+     * @see java.security.IdentityScope#addIdentity(java.security.Identity)
+     */
+    public synchronized void addIdentity(Identity identity)
+            throws KeyManagementException {
+        if (identity == null) {
+            throw new NullPointerException(Messages.getString("security.92")); //$NON-NLS-1$
+        }
+
+        String name = identity.getName();
+        if (names.containsKey(name)) {
+            throw new KeyManagementException(Messages.getString("security.93", name)); //$NON-NLS-1$
+        }
+
+        PublicKey key = identity.getPublicKey();
+        if (key != null && keys.containsKey(key)) {
+            throw new KeyManagementException(Messages.getString("security.94", key)); //$NON-NLS-1$
+        }
+
+        names.put(name, identity);
+        if (key != null) {
+            keys.put(key, identity);
+        }
+    }
+
+    /**
+     * @see java.security.IdentityScope#removeIdentity(java.security.Identity)
+     */
+    public synchronized void removeIdentity(Identity identity)
+            throws KeyManagementException {
+
+        //Exception caught = null;
+        if (identity == null) {
+            throw new NullPointerException(Messages.getString("security.92")); //$NON-NLS-1$
+        }
+
+        String name = identity.getName();
+        if (name == null) {
+            throw new NullPointerException(Messages.getString("security.95")); //$NON-NLS-1$
+        }
+
+        boolean contains = names.containsKey(name);
+        names.remove(name);
+
+        PublicKey key = identity.getPublicKey();
+        
+        if (key != null) {
+            contains = contains || keys.containsKey(key);
+            keys.remove(key);
+        }
+        
+        if (!contains) {
+            throw new KeyManagementException(Messages.getString("security.96")); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * @see java.security.IdentityScope#identities()
+     */
+    public Enumeration identities() {
+        return names.elements();
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/UnresolvedPrincipal.java b/libcore/security/src/main/java/org/apache/harmony/security/UnresolvedPrincipal.java
new file mode 100644
index 0000000..f270baf
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/UnresolvedPrincipal.java
@@ -0,0 +1,144 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security;
+
+import java.security.Principal;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * Descriptive implementation of Principal, which holds a name and a classname
+ * of unresolved principal. It is used to define an arbitrary Principal which
+ * may be not yet instantiated and authenticated. 
+ * <br>
+ * This concept is somewhat similar to UnresolvedPermission. A principal-based 
+ * policy may grant permissions depending on what Principals own the current 
+ * execution thread. So the policy refers to this model definition of 
+ * acceptable principal and compares it with the actual principal. 
+ * 
+ * @see org.apache.harmony.security.PolicyEntry
+ * @see org.apache.harmony.security.fortress.DefaultPolicy
+ */
+public final class UnresolvedPrincipal implements Principal {
+
+    /** 
+     * Wildcard value denotes any class and/or any name. 
+     */
+    public static final String WILDCARD = DefaultPolicyScanner.PrincipalEntry.WILDCARD;
+
+    // Class name
+    private final String klass;
+
+    // Principal name
+    private final String name;
+
+    /**
+     * Constructs a a new definition of a Principal with specified
+     * parameters. 
+     * @param klass fully qualified class name, may be wildcard
+     * @param name name of principal, may be wildcard
+     * @throws IllegalArgumentException if <code>klass</code> value 
+     * is <code>null </code> or is empty string 
+     */
+    public UnresolvedPrincipal(String klass, String name) {
+        if (klass == null || klass.length() == 0) {
+            throw new IllegalArgumentException(Messages.getString("security.91")); //$NON-NLS-1$
+        }
+
+        this.klass = klass;
+        this.name = name;
+    }
+
+    /**
+     * Returns name of a modeled Principal, or wildcard 
+     * if any name is acceptable.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /** 
+     * Returns fully qualified class name of a modeled Principal,
+     * or wildcard if any class is acceptable. 
+     */
+    public String getClassName() {
+        return klass;
+    }
+
+    /**
+     * Returns <code>true</code> if compared object is a Principal
+     * matching this definition, or if it is an UnresolvedPrincipal, 
+     * which defines the same Principal; <code>false</code> otherwise.  
+     */
+    public boolean equals(Object that) {
+        if (that instanceof UnresolvedPrincipal) {
+            UnresolvedPrincipal up = (UnresolvedPrincipal) that;
+            return klass.equals(up.klass)
+                    && (name == null ? up.name == null : name.equals(up.name));
+        }
+        if (that instanceof Principal) {
+            return implies((Principal) that);
+        }
+        return false;
+    }
+
+    /** 
+     * Returns <code>true</code> if compared object is a Principal
+     * exactly matching this definition. Namely, if the fully qualified name 
+     * of class of passed Principal is equal to the class name value
+     * of this definition and the name of passed Principal is equal to 
+     * the name value of this definition, or if this definition allows
+     * any class or name, respectively.  
+     * Otherwise returns <code>false</code> .
+     */
+    public boolean implies(Principal another) {
+        return (another != null)
+                && (WILDCARD.equals(klass) 
+                    || klass.equals(another.getClass().getName())
+                && (WILDCARD.equals(name) 
+                    || (name == null ? another.getName() == null 
+                        : name.equals(another.getName()))));
+    }
+
+    /** 
+     * Returns the hash code value for this object. 
+     */
+    public int hashCode() {
+        int hash = 0;
+        if (name != null) {
+            hash ^= name.hashCode();
+        }
+        if (klass != null) {
+            hash ^= klass.hashCode();
+        }
+        return hash;
+    }
+
+    /** 
+     * Returns a string describing this model of Principal.
+     * The format is 'Principal classname &quot;name&quot;'.
+     */
+    public String toString() {
+        return "Principal " + klass + " \"" + name + "\""; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Any.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Any.java
new file mode 100644
index 0000000..61bec47
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Any.java
@@ -0,0 +1,126 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.io.IOException;
+
+
+/**
+ * This class represents ASN.1 ANY type.
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public class ASN1Any extends ASN1Type {
+
+    // default implementation
+    private static final ASN1Any ASN1= new ASN1Any();
+
+    /**
+     * Constructs ASN.1 ANY type
+     * 
+     * The constructor is provided for inheritance purposes
+     * when there is a need to create a custom ASN.1 ANY type.
+     * To get a default implementation it is recommended to use
+     * getInstance() method.
+     */
+    public ASN1Any() {
+        super(TAG_ANY); // has not tag number
+    }
+
+    /**
+     * Returns ASN.1 ANY type default implementation
+     * 
+     * The default implementation works with full encoding
+     * that is represented as raw byte array.
+     *
+     * @return ASN.1 ANY type default implementation
+     */
+    public static ASN1Any getInstance() {
+        return ASN1;
+    }
+
+    //
+    //
+    // Decode
+    //
+    //
+
+    /**
+     * Tests provided identifier.
+     *
+     * @param identifier - identifier to be verified
+     * @return - true
+     */
+    public final boolean checkTag(int identifier) {
+        return true; //all tags are OK
+    }
+
+    public Object decode(BerInputStream in) throws IOException {
+
+        // only read content, doesn't check it
+        in.readContent();
+
+        if (in.isVerify) {
+            return null;
+        }
+        return getDecodedObject(in);
+    }
+
+    /**
+     * Extracts array of bytes that represents full encoding from BER input
+     * stream.
+     * 
+     * @param in -
+     *            BER input stream
+     * @return array of bytes
+     */
+    public Object getDecodedObject(BerInputStream in) throws IOException {
+        byte[] bytesEncoded = new byte[in.offset - in.tagOffset];
+        System.arraycopy(in.buffer, in.tagOffset, bytesEncoded, 0,
+                bytesEncoded.length);
+        return bytesEncoded;
+    }
+
+    //
+    //
+    // Encode
+    //
+    //
+
+    public void encodeASN(BerOutputStream out) {
+        out.encodeANY();
+    }
+
+    public void encodeContent(BerOutputStream out) {
+        out.encodeANY();
+    }
+
+    public void setEncodingContent(BerOutputStream out) {
+        out.length = ((byte[]) out.content).length;
+    }
+
+    public int getEncodedLength(BerOutputStream out) {
+        return out.length;
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1BitString.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1BitString.java
new file mode 100644
index 0000000..e31b99e
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1BitString.java
@@ -0,0 +1,235 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.io.IOException;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * This class represents ASN.1 Bitstring type.
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public class ASN1BitString extends ASN1StringType {
+
+    // default implementation
+    private static final ASN1BitString ASN1 = new ASN1BitString();
+
+    /**
+     * Constructs ASN.1 Bitstring type
+     * 
+     * The constructor is provided for inheritance purposes
+     * when there is a need to create a custom ASN.1 Bitstring type.
+     * To get a default implementation it is recommended to use
+     * getInstance() method.
+     */
+    public ASN1BitString() {
+        super(TAG_BITSTRING);
+    }
+
+    /**
+     * Returns ASN.1 Bitstring type default implementation
+     * 
+     * The default implementation works with encoding
+     * that is represented as BitString object.
+     *
+     * @return ASN.1 Bitstring type default implementation
+     * @see org.apache.harmony.security.asn1.BitString
+     */
+    public static ASN1BitString getInstance() {
+        return ASN1;
+    }
+
+    //
+    //
+    // Decode
+    //
+    //
+
+    public Object decode(BerInputStream in) throws IOException {
+
+        in.readBitString();
+
+        if (in.isVerify) {
+            return null;
+        }
+        return getDecodedObject(in);
+    }
+
+    /**
+     * Extracts BitString object from BER input stream.
+     *
+     * @param in - BER input stream
+     * @return BitString object
+     */
+    public Object getDecodedObject(BerInputStream in) throws IOException {
+        byte[] bytes = new byte[in.length - 1];
+        System.arraycopy(in.buffer, in.contentOffset + 1, bytes, 0,
+                in.length - 1);
+        return new BitString(bytes, in.buffer[in.contentOffset]);
+    }
+
+    //
+    // Encode
+    //
+
+    public void encodeContent(BerOutputStream out) {
+        out.encodeBitString();
+    }
+
+    public void setEncodingContent(BerOutputStream out) {
+        out.length = ((BitString) out.content).bytes.length + 1;
+    }
+
+    //
+    //
+    // Named Bit List
+    //
+    //
+
+    /**
+     * Default implementation for ASN.1 Named Bitstring type 
+     * 
+     * The default implementation works with encoding
+     * that is mapped to array of boolean.
+     */
+    public static class ASN1NamedBitList extends ASN1BitString {
+
+        private static final byte[] SET_MASK = { (byte) 128, 64, 32, 16, 8, 4,
+                2, 1 };
+
+        private static final BitString emptyString = new BitString(
+                new byte[] {}, 0);
+
+        private static final int INDEFINITE_SIZE = -1;
+
+        private final int minBits;
+
+        private final int maxBits;
+
+        public ASN1NamedBitList() {
+            this.minBits = INDEFINITE_SIZE;
+            this.maxBits = INDEFINITE_SIZE;
+        }
+
+        public ASN1NamedBitList(int minBits) {
+            this.minBits = minBits;
+            this.maxBits = INDEFINITE_SIZE;
+        }
+
+        public ASN1NamedBitList(int minBits, int maxBits) {
+            this.minBits = minBits;
+            this.maxBits = maxBits;
+        }
+
+        public Object getDecodedObject(BerInputStream in) throws IOException {
+
+            boolean[] value = null;
+
+            int unusedBits = in.buffer[in.contentOffset];
+            int bitsNumber = (in.length - 1) * 8 - unusedBits;
+
+            if (maxBits == INDEFINITE_SIZE) {
+                if (minBits == INDEFINITE_SIZE) {
+                    value = new boolean[bitsNumber];
+                } else {
+                    if (bitsNumber > minBits) {
+                        value = new boolean[bitsNumber];
+                    } else {
+                        value = new boolean[minBits];
+                    }
+                }
+            } else {
+                if (bitsNumber > maxBits) {
+                    throw new ASN1Exception(
+                            Messages.getString("security.97")); //FIXME message //$NON-NLS-1$
+                }
+                value = new boolean[maxBits];
+            }
+
+            if (bitsNumber == 0) {
+                // empty bit string
+                return value;
+            }
+
+            int i = 1;
+            int j = 0;
+            byte octet = in.buffer[in.contentOffset + i];
+            for (int size = in.length - 1; i < size; i++) {
+
+                for (int k = 0; k < 8; k++, j++) {
+                    value[j] = (SET_MASK[k] & octet) != 0;
+                }
+                i++;
+                octet = in.buffer[in.contentOffset + i];
+            }
+
+            // final octet
+            for (int k = 0; k < (8 - unusedBits); k++, j++) {
+                value[j] = (SET_MASK[k] & octet) != 0;
+            }
+
+            return value;
+        }
+
+        public void setEncodingContent(BerOutputStream out) {
+
+            boolean[] toEncode = (boolean[]) out.content;
+
+            int index = toEncode.length - 1;
+            while (index > -1 && !toEncode[index]) {
+                index--;
+            }
+
+            if (index == -1) {
+                out.content = emptyString;
+                out.length = 1;
+            } else {
+                int unusedBits = 7 - index % 8;
+                byte[] bytes = new byte[index / 8 + 1];
+
+                int j = 0;
+                index = bytes.length - 1;
+                for (int i = 0; i < index; i++) {
+                    for (int k = 0; k < 8; k++, j++) {
+                        if (toEncode[j]) {
+                            bytes[i] = (byte) (bytes[i] | SET_MASK[k]);
+                        }
+                    }
+                }
+
+                //final octet
+                for (int k = 0; k < (8 - unusedBits); k++, j++) {
+                    if (toEncode[j]) {
+                        bytes[index] = (byte) (bytes[index] | SET_MASK[k]);
+                    }
+                }
+
+                out.content = new BitString(bytes, unusedBits);
+                out.length = bytes.length + 1;
+            }
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Boolean.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Boolean.java
new file mode 100644
index 0000000..d40c2bf
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Boolean.java
@@ -0,0 +1,104 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.io.IOException;
+
+
+/**
+ * This class represents ASN.1 Boolean type.
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public class ASN1Boolean extends ASN1Primitive {
+
+    // default implementation
+    private static final ASN1Boolean ASN1 = new ASN1Boolean();
+
+    /**
+     * Constructs ASN.1 Boolean type
+     * 
+     * The constructor is provided for inheritance purposes
+     * when there is a need to create a custom ASN.1 Boolean type.
+     * To get a default implementation it is recommended to use
+     * getInstance() method.
+     */
+    public ASN1Boolean() {
+        super(TAG_BOOLEAN);
+    }
+
+    /**
+     * Returns ASN.1 Boolean type default implementation
+     * 
+     * The default implementation works with encoding
+     * that is represented as Boolean object.
+     *
+     * @return ASN.1 Boolean type default implementation
+     */
+    public static ASN1Boolean getInstance() {
+        return ASN1;
+    }
+
+    //
+    //
+    // Decode
+    //
+    //
+
+    public Object decode(BerInputStream in) throws IOException {
+        in.readBoolean();
+
+        if (in.isVerify) {
+            return null;
+        }
+        return getDecodedObject(in);
+    }
+
+    /**
+     * Extracts Boolean object from BER input stream.
+     *
+     * @param in - BER input stream
+     * @return java.lang.Boolean object
+     */
+    public Object getDecodedObject(BerInputStream in) throws IOException {
+        if (in.buffer[in.contentOffset] == 0) {
+            return Boolean.FALSE;
+        }
+        return Boolean.TRUE;
+    }
+
+    //
+    //
+    // Encode
+    //
+    //
+
+    public void encodeContent(BerOutputStream out) {
+        out.encodeBoolean();
+    }
+
+    public void setEncodingContent(BerOutputStream out) {
+        out.length = 1;
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Choice.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Choice.java
new file mode 100644
index 0000000..1f5534d
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Choice.java
@@ -0,0 +1,356 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.TreeMap;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * This abstract class represents ASN.1 Choice type.
+ * 
+ * To implement custom ASN.1 choice type an application class
+ * must provide implementation for the following methods:
+ *     getIndex()
+ *     getObjectToEncode()
+ * 
+ * There are two ways to implement custom ASN.1 choice type:
+ * with application class that represents ASN.1 custom choice type or without. 
+ * The key point is how a value of choice type is stored by application classes.
+ * 
+ * For example, let's consider the following ASN.1 notations
+ * (see http://www.ietf.org/rfc/rfc3280.txt)
+ * 
+ * Time ::= CHOICE {
+ *       utcTime        UTCTime,
+ *       generalTime    GeneralizedTime
+ * }
+ * 
+ * Validity ::= SEQUENCE {
+ *       notBefore      Time,
+ *       notAfter       Time 
+ *  }
+ * 
+ * 1)First approach:
+ * No application class to represent ASN.1 Time notation
+ * 
+ * The Time notation is a choice of different time formats: UTC and Generalized.
+ * Both of them are mapped to java.util.Date object, so an application
+ * class that represents ASN.1 Validity notation may keep values
+ * as Date objects.
+ * 
+ * So a custom ASN.1 Time choice type should map its notation to Date object.
+ * 
+ * class Time {
+ * 
+ *     // custom ASN.1 choice class: maps Time to is notation
+ *     public static final ASN1Choice asn1 = new ASN1Choice(new ASN1Type[] {
+ *         ASN1GeneralizedTime.asn1, ASN1UTCTime.asn1 }) {
+ *
+ *         public int getIndex(java.lang.Object object) {
+ *             return 0; // always encode as ASN1GeneralizedTime
+ *         }
+ *
+ *         public Object getObjectToEncode(Object object) {
+ *         
+ *             // A value to be encoded value is a Date object
+ *             // pass it to custom time class  
+ *             return object;
+ *         }
+ *     };
+ * }
+ * 
+ * class Validity {
+ * 
+ *     private Date notBefore;    // choice as Date 
+ *     private Date notAfter;     // choice as Date
+ * 
+ *     ... // constructors and other methods go here
+ * 
+ *     // custom ASN.1 sequence class: maps Validity class to is notation
+ *     public static final ASN1Sequence ASN1
+ *         = new ASN1Sequence(new ASN1Type[] {Time.asn1, Time.asn1 }) {
+ * 
+ *         protected Object getObject(Object[] values) {
+ * 
+ *             // ASN.1 Time choice passed Data object - use it 
+ *             return new Validity((Date) values[0], (Date) values[1]);
+ *         }
+ *
+ *         protected void getValues(Object object, Object[] values) {
+ *
+ *             Validity validity = (Validity) object;
+ *
+ *             // pass Date objects to ASN.1 Time choice
+ *             values[0] = validity.notBefore;
+ *             values[1] = validity.notAfter;
+ *         }
+ *     }
+ * }
+ * 
+ * 2)Second approach:
+ * There is an application class to represent ASN.1 Time notation
+ * 
+ * If it is a matter what time format should be used to decode/encode
+ * Date objects a class to represent ASN.1 Time notation must be created.
+ * 
+ * For example,
+ *  
+ * class Time {
+ * 
+ *     private Date utcTime; 
+ *     private Date gTime;
+ * 
+ *     ... // constructors and other methods go here
+ *  
+ *     // custom ASN.1 choice class: maps Time to is notation
+ *     public static final ASN1Choice asn1 = new ASN1Choice(new ASN1Type[] {
+ *         ASN1GeneralizedTime.asn1, ASN1UTCTime.asn1 }) {
+ *
+ *         public Object getDecodedObject(BerInputStream in) {
+ *
+ *             // create Time object to pass as decoded value
+ *             Time time = new Time();
+ * 
+ *             if (in.choiceIndex==0) {
+ *                 // we decoded GeneralizedTime
+ *                 // store decoded Date value in corresponding field
+ *                 time.gTime = in.content;
+ *                 // return it
+ *                 return time;
+ *             } else {
+ *                 // we decoded UTCTime
+ *                 // store decoded Date value in corresponding field
+ *                 time.utcTime = in.content;
+ *                 // return it
+ *                 return time;
+ *             }
+ *         }
+ *
+ *         public int getIndex(java.lang.Object object) {
+ *             Time time = (Time)object;
+ *             if(time.utcTime!=null){
+ *                 // encode Date as UTCTime
+ *                 return 1;
+ *             } else {
+ *                 // otherwise encode Date as GeneralizedTime
+ *                 return 0;
+ *             } 
+ *         }
+ *
+ *         public Object getObjectToEncode(Object object) {
+ *             Time time = (Time)object;
+ *             if(time.utcTime!=null){
+ *                 // encode Date as UTCTime
+ *                 return 1;
+ *             } else {
+ *                 // otherwise encode Date as GeneralizedTime
+ *                 return 0;
+ *             } 
+ *         }
+ *     };
+ * }
+ *
+ * So now Validity class must keep all values in Time object
+ * and its custom ASN.1 sequence class must handle this class of objects
+ *
+ * class Validity {
+ * 
+ *     private Time notBefore;    // now it is a Time!!! 
+ *     private Time notAfter;     // now it is a Time!!!
+ * 
+ *     ... // constructors and other methods go here
+ * 
+ *     // custom ASN.1 sequence class: maps Validity class to is notation
+ *     public static final ASN1Sequence ASN1
+ *         = new ASN1Sequence(new ASN1Type[] {Time.asn1, Time.asn1 }) {
+ * 
+ *         protected Object getObject(Object[] values) {
+ * 
+ *             // We've gotten Time objects here !!!
+ *             return new Validity((Time) values[0], (Time) values[1]);
+ *         }
+ *
+ *         protected void getValues(Object object, Object[] values) {
+ *
+ *             Validity validity = (Validity) object;
+ *
+ *             // pass Time objects to ASN.1 Time choice
+ *             values[0] = validity.notBefore;
+ *             values[1] = validity.notAfter;
+ *         }
+ *     }
+ * }
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public abstract class ASN1Choice extends ASN1Type {
+
+    public final ASN1Type[] type;
+
+    // identifiers table: [2][number of distinct identifiers]
+    // identifiers[0]: stores identifiers (includes nested choices)
+    // identifiers[1]: stores identifiers' indexes in array of types
+    private final int[][] identifiers;
+
+    /**
+     * Constructs ASN.1 choice type.
+     * 
+     * @param type -
+     *            an array of one or more ASN.1 type alternatives.
+     * @throws IllegalArgumentException -
+     *             type parameter is invalid
+     */
+    public ASN1Choice(ASN1Type[] type) {
+        super(TAG_CHOICE); // has not tag number
+
+        if (type.length == 0) {
+            throw new IllegalArgumentException(Messages.getString("security.10E", //$NON-NLS-1$
+                    getClass().getName()));
+        }
+
+        // create map of all identifiers
+        TreeMap map = new TreeMap();
+        for (int index = 0; index < type.length; index++) {
+
+            ASN1Type t = type[index];
+
+            if (t instanceof ASN1Any) {
+                // ASN.1 ANY is not allowed,
+                // even it is a single component (not good for nested choices)
+                throw new IllegalArgumentException(Messages.getString("security.10F", //$NON-NLS-1$
+                        getClass().getName())); // FIXME name
+            } else if (t instanceof ASN1Choice) {
+
+                // add all choice's identifiers
+                int[][] choiceToAdd = ((ASN1Choice) t).identifiers;
+                for (int j = 0; j < choiceToAdd[0].length; j++) {
+                    addIdentifier(map, choiceToAdd[0][j], index);
+                }
+                continue;
+            }
+
+            // add primitive identifier
+            if (t.checkTag(t.id)) {
+                addIdentifier(map, t.id, index);
+            }
+
+            // add constructed identifier
+            if (t.checkTag(t.constrId)) {
+                addIdentifier(map, t.constrId, index);
+            }
+        }
+
+        // fill identifiers array
+        int size = map.size();
+        identifiers = new int[2][size];
+        Iterator it = map.keySet().iterator();
+        for (int i = 0; i < size; i++) {
+            BigInteger identifier = (BigInteger) it.next();
+
+            identifiers[0][i] = identifier.intValue();
+            identifiers[1][i] = ((BigInteger) map.get(identifier)).intValue();
+        }
+
+        this.type = type;
+    }
+
+    private void addIdentifier(TreeMap map, int identifier, int index){
+        if (map.put(BigInteger.valueOf(identifier), BigInteger.valueOf(index)) != null) {
+            throw new IllegalArgumentException(Messages.getString("security.10F", //$NON-NLS-1$
+                    getClass().getName())); // FIXME name
+        }
+    }
+    
+    //
+    //
+    // DECODE
+    //
+    //
+
+    /**
+     * Tests whether one of choice alternatives has the same identifier or not.
+     * 
+     * @param identifier -
+     *            ASN.1 identifier to be verified
+     * @return - true if one of choice alternatives has the same identifier,
+     *         otherwise false;
+     */
+    public final boolean checkTag(int identifier) {
+        return Arrays.binarySearch(identifiers[0], identifier) >= 0;
+    }
+
+    public Object decode(BerInputStream in) throws IOException {
+
+        int index = Arrays.binarySearch(identifiers[0], in.tag);
+        if (index < 0) {
+            throw new ASN1Exception(Messages.getString("security.110", //$NON-NLS-1$
+                    getClass().getName()));// FIXME message
+        }
+
+        index = identifiers[1][index];
+
+        in.content = type[index].decode(in);
+
+        // set index for getDecodedObject method
+        in.choiceIndex = index;
+
+        if (in.isVerify) {
+            return null;
+        }
+        return getDecodedObject(in);
+    }
+    
+    //
+    //
+    // ENCODE
+    //
+    //
+
+    public void encodeASN(BerOutputStream out) {
+        encodeContent(out);
+    }
+
+    public final void encodeContent(BerOutputStream out) {
+        out.encodeChoice(this);
+    }
+
+    /**
+     * TODO Put method description here
+     *
+     * @param object - an object to be encoded
+     * @return
+     */
+    public abstract int getIndex(Object object);
+
+    public abstract Object getObjectToEncode(Object object);
+
+    public final void setEncodingContent(BerOutputStream out) {
+        out.getChoiceLength(this);
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Constants.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Constants.java
new file mode 100644
index 0000000..99cd3b6
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Constants.java
@@ -0,0 +1,96 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+/**
+ * ASN.1 and some other constants holder interface
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+public interface ASN1Constants {
+    /**
+     * Tag classes
+     */
+    int CLASS_UNIVERSAL = 0;
+    int CLASS_APPLICATION = 64;
+    int CLASS_CONTEXTSPECIFIC = 128;
+    int CLASS_PRIVATE = 192;
+
+    /**
+     * Tag Primitive/Constructed (P/C) flag
+     */
+    int PC_PRIMITIVE = 0;
+    int PC_CONSTRUCTED = 32;
+
+    /**
+     * Universal class tag assignments
+     */
+    int TAG_BOOLEAN = 1;
+    int TAG_INTEGER = 2;
+    int TAG_BITSTRING = 3;
+    int TAG_OCTETSTRING = 4;
+    int TAG_NULL = 5;
+    int TAG_OID = 6;
+    int TAG_OBJDESCRIPTOR = 7;
+    int TAG_EXTERNAL = 8;
+    int TAG_INSTANCEOF = TAG_EXTERNAL;
+    int TAG_REAL = 9;
+    int TAG_ENUM = 10;
+    int TAG_EMBEDDEDPDV = 11;
+    int TAG_UTF8STRING = 12;
+    int TAG_RELATIVEOID = 13;
+    int TAG_SEQUENCE = 16;
+    int TAG_SEQUENCEOF = TAG_SEQUENCE;
+    int TAG_SET = 17;
+    int TAG_SETOF = TAG_SET;
+    int TAG_NUMERICSTRING = 18;
+    int TAG_PRINTABLESTRING = 19;
+    int TAG_TELETEXSTRING = 20;
+    int TAG_T61STRING = TAG_TELETEXSTRING;
+    int TAG_VIDEOTEXSTRING = 21;
+    int TAG_IA5STRING = 22;
+    int TAG_UTCTIME = 23;
+    int TAG_GENERALIZEDTIME = 24;
+    int TAG_GRAPHICSTRING = 25;
+    int TAG_VISIBLESTRING = 26;
+    int TAG_ISO646STRING = TAG_VISIBLESTRING;
+    int TAG_GENERALSTRING = 27;
+    int TAG_UNIVERSALSTRING = 28;
+    int TAG_BMPSTRING = 30;
+
+    int TAG_C_BITSTRING = TAG_BITSTRING | PC_CONSTRUCTED;
+    int TAG_C_OCTETSTRING = TAG_OCTETSTRING | PC_CONSTRUCTED;
+    int TAG_C_UTF8STRING = TAG_UTF8STRING | PC_CONSTRUCTED;
+    int TAG_C_SEQUENCE = TAG_SEQUENCE | PC_CONSTRUCTED;
+    int TAG_C_SEQUENCEOF = TAG_SEQUENCEOF | PC_CONSTRUCTED;
+    int TAG_C_SET = TAG_SET | PC_CONSTRUCTED;
+    int TAG_C_SETOF = TAG_SETOF | PC_CONSTRUCTED;
+    int TAG_C_UTCTIME = TAG_UTCTIME | PC_CONSTRUCTED;
+    int TAG_C_GENERALIZEDTIME = TAG_GENERALIZEDTIME | PC_CONSTRUCTED;
+ 
+    /**
+     * Not from the ASN.1 specs. For implementation purposes.
+     */
+    int TAG_ANY = 0;
+    int TAG_CHOICE = TAG_ANY;
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Constructured.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Constructured.java
new file mode 100644
index 0000000..aba9b32
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Constructured.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+
+/**
+ * This abstract class is the super class for all constructed ASN.1 types
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public abstract class ASN1Constructured extends ASN1Type {
+
+    public ASN1Constructured(int tagNumber) {
+        super(CLASS_UNIVERSAL, tagNumber);
+    }
+
+    public ASN1Constructured(int tagClass, int tagNumber) {
+        super(tagClass, tagNumber);
+    }
+    
+    /**
+     * Tests provided identifier.
+     *
+     * @param identifier - identifier to be verified
+     * @return - true if identifier correspond to constructed identifier of
+     *           this ASN.1 type, otherwise false
+     */
+    public final boolean checkTag(int identifier) {
+        return this.constrId == identifier;
+    }
+    
+    /**
+     *
+     */
+    public void encodeASN(BerOutputStream out) {
+        out.encodeTag(constrId);
+        encodeContent(out);
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Enumerated.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Enumerated.java
new file mode 100644
index 0000000..5fa02f5
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Enumerated.java
@@ -0,0 +1,104 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.io.IOException;
+
+
+/**
+ * This class represents ASN.1 Enumerated type.
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public class ASN1Enumerated extends ASN1Primitive {
+
+    // default implementation
+    private static final ASN1Enumerated ASN1 = new ASN1Enumerated();
+
+    /**
+     * Constructs ASN.1 Enumerated type
+     * 
+     * The constructor is provided for inheritance purposes
+     * when there is a need to create a custom ASN.1 Enumerated type.
+     * To get a default implementation it is recommended to use
+     * getInstance() method.
+     */
+    public ASN1Enumerated() {
+        super(TAG_ENUM);
+    }
+
+    /**
+     * Returns ASN.1 Enumerated type default implementation
+     * 
+     * The default implementation works with encoding
+     * that is represented as byte array.
+     *
+     * @return ASN.1 Enumerated type default implementation
+     */
+    public static ASN1Enumerated getInstance() {
+        return ASN1;
+    }
+
+    //
+    //
+    // Decode
+    //
+    //
+
+    public Object decode(BerInputStream in) throws IOException {
+        in.readEnumerated();
+
+        if (in.isVerify) {
+            return null;
+        }
+        return getDecodedObject(in);
+    }
+
+    /**
+     * Extracts array of bytes from BER input stream.
+     *
+     * @param in - BER input stream
+     * @return array of bytes
+     */
+    public Object getDecodedObject(BerInputStream in) throws IOException {
+        byte[] bytesEncoded = new byte[in.length];
+        System.arraycopy(in.buffer, in.contentOffset, bytesEncoded, 0,
+                in.length);
+        return bytesEncoded;
+    }
+
+    //
+    //
+    // Encode
+    //
+    //
+
+    public void encodeContent(BerOutputStream out) {
+        out.encodeInteger();
+    }
+
+    public void setEncodingContent(BerOutputStream out) {
+        out.length = ((byte[]) out.content).length;
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Exception.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Exception.java
new file mode 100644
index 0000000..f214f26
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Exception.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.io.IOException;
+
+/**
+ * Thrown by decoder/encoder stream to indicate violation of encoding rules.
+ */
+
+public class ASN1Exception extends IOException {
+
+    /**
+     * @serial
+     */
+    private static final long serialVersionUID = -3561981263989123987L;
+
+    /**
+     * Constructs an ASN1Exception without a message. 
+     */
+    public ASN1Exception(){
+    }
+
+    /**
+     * Constructs an ASN1Exception with a message. 
+     * 
+     * @param message - a string that describes encoding violation 
+     */
+    public ASN1Exception(String message){
+        super(message);
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Explicit.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Explicit.java
new file mode 100644
index 0000000..fc42f61
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Explicit.java
@@ -0,0 +1,110 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.io.IOException;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * This class represents explicitly tagged ASN.1 type.
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public final class ASN1Explicit extends ASN1Constructured {
+
+    /**
+     * Tagged type
+     */
+    public final ASN1Type type;
+
+    /**
+     * Constructs explicitly tagged ASN.1 type
+     * with context-specific tag class and specified tag number. 
+     * 
+     * @param tagNumber - ASN.1 tag number
+     * @param type - ASN.1 type to be tagged
+     * @throws IllegalArgumentException - if tagNumber is invalid
+     */
+    public ASN1Explicit(int tagNumber, ASN1Type type) {
+        this(CLASS_CONTEXTSPECIFIC, tagNumber, type);
+    }
+
+    /**
+     * Constructs explicitly tagged ASN.1 type.
+     * 
+     * @param tagClass - ASN.1 tag class.
+     * @param tagNumber - ASN.1 tag number
+     * @param type - ASN.1 type to be tagged
+     * @throws IllegalArgumentException - if tagClass or tagNumber is invalid
+     */
+    public ASN1Explicit(int tagClass, int tagNumber, ASN1Type type) {
+        super(tagClass, tagNumber);
+
+        this.type = type;
+    }
+
+    //
+    //
+    // Decode
+    //
+    //
+
+    public Object decode(BerInputStream in) throws IOException {
+        if (constrId != in.tag) {
+            throw new ASN1Exception(
+                    Messages.getString("security.13F", //$NON-NLS-1$
+                    new Object[] { in.tagOffset, Integer.toHexString(constrId),
+                            Integer.toHexString(in.tag) }));
+        }
+        in.next();
+
+        in.content = type.decode(in);
+
+        if (in.isVerify) {
+            return null;
+        }
+        return getDecodedObject(in);
+    }
+
+    //
+    //
+    // Encode
+    //
+    //
+
+    public void encodeContent(BerOutputStream out) {
+        out.encodeExplicit(this);
+    }
+
+    public void setEncodingContent(BerOutputStream out) {
+        out.getExplicitLength(this);
+    }
+
+    public String toString() {
+        //FIXME fix performance
+        return super.toString() + " for type " + type; //$NON-NLS-1$
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1GeneralizedTime.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1GeneralizedTime.java
new file mode 100644
index 0000000..4ec103b
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1GeneralizedTime.java
@@ -0,0 +1,120 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.TimeZone;
+
+
+/**
+ * This class represents ASN.1 GeneralizedTime type.
+ * 
+ * According to X.680 specification this type is defined as follows:
+ *     GeneralizedTime ::= [UNIVERSAL 24] IMPLICIT VisibleString
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public class ASN1GeneralizedTime extends ASN1Time {
+
+    // default implementation
+    private static final ASN1GeneralizedTime ASN1 = new ASN1GeneralizedTime();
+
+    /**
+     * Constructs ASN.1 GeneralizedTime type
+     * 
+     * The constructor is provided for inheritance purposes
+     * when there is a need to create a custom ASN.1 GeneralizedTime type.
+     * To get a default implementation it is recommended to use
+     * getInstance() method.
+     */
+    public ASN1GeneralizedTime() {
+        super(TAG_GENERALIZEDTIME);
+    }
+
+    /**
+     * Returns ASN.1 GeneralizedTime type default implementation
+     * 
+     * The default implementation works with encoding
+     * that is represented as Date object.
+     *
+     * @return ASN.1 GeneralizedTime type default implementation
+     */
+    public static ASN1GeneralizedTime getInstance() {
+        return ASN1;
+    }
+
+    //
+    //
+    // Decode
+    //
+    //
+
+    public Object decode(BerInputStream in) throws IOException {
+        in.readGeneralizedTime();
+
+        if (in.isVerify) {
+            return null;
+        }
+        return getDecodedObject(in);
+    }
+
+    //
+    //
+    // Encode
+    //
+    //
+
+    public void encodeContent(BerOutputStream out) {
+        out.encodeGeneralizedTime();
+    }
+
+    // FIXME support only one format for encoding, do we need others?
+    //
+    // According to X.680:
+    // four digit year, seconds always presented
+    // and fractional-seconds elements without
+    // trailing 0's (must be cut later from content)
+    private final static String GEN_PATTERN = "yyyyMMddHHmmss.SSS"; //$NON-NLS-1$
+
+    public void setEncodingContent(BerOutputStream out) {
+
+        SimpleDateFormat sdf = new SimpleDateFormat(GEN_PATTERN);
+        sdf.setTimeZone(TimeZone.getTimeZone("UTC")); //$NON-NLS-1$
+        String temp = sdf.format(out.content);
+        // cut off trailing 0s
+        int nullId;
+        int currLength;
+        while (((nullId = temp.lastIndexOf('0', currLength = temp.length() - 1)) != -1)
+                & (nullId == currLength)) {
+            temp = temp.substring(0, nullId);
+        }
+        // deal with point (cut off if it is last char)
+        if (temp.charAt(currLength) == '.') {
+            temp = temp.substring(0, currLength);
+        }
+        out.content = (temp + "Z").getBytes(); //$NON-NLS-1$
+        out.length = ((byte[]) out.content).length;
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Implicit.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Implicit.java
new file mode 100644
index 0000000..df7d395
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Implicit.java
@@ -0,0 +1,172 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.io.IOException;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * Implicitly tagged ASN.1 type.
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+public class ASN1Implicit extends ASN1Type {
+
+    // primitive type of tagging
+    private static final int TAGGING_PRIMITIVE = 0;
+
+    // constructed type of tagging
+    private static final int TAGGING_CONSTRUCTED = 1;
+
+    // string type of tagging
+    private static final int TAGGING_STRING = 2;
+
+    // tagged ASN.1 type
+    private final ASN1Type type;
+
+    // type of tagging. There are three of them
+    // 1) primitive: only primitive identifier is valid
+    // 2) constructed: only constructed identifier is valid
+    // 3) string: both identifiers are valid
+    private final int taggingType;
+
+    /**
+     * Constructs implicitly tagged ASN.1 type
+     * with context-specific tag class and specified tag number. 
+     * 
+     * @param tagNumber - ASN.1 tag number
+     * @param type - ASN.1 type to be tagged
+     * @throws IllegalArgumentException - if tagNumber or type is invalid
+     */
+    public ASN1Implicit(int tagNumber, ASN1Type type) {
+        this(CLASS_CONTEXTSPECIFIC, tagNumber, type);
+    }
+
+    /**
+     * Constructs implicitly tagged ASN.1 type
+     * 
+     * @param tagClass - ASN.1 tag class.
+     * @param tagNumber - ASN.1 tag number
+     * @param type - ASN.1 type to be tagged
+     * @throws IllegalArgumentException - if tagNumber, tagClass or type is invalid
+     */
+    public ASN1Implicit(int tagClass, int tagNumber, ASN1Type type) {
+        super(tagClass, tagNumber);
+
+        if ((type instanceof ASN1Choice) || (type instanceof ASN1Any)) {
+            // According to X.680:
+            // 'The IMPLICIT alternative shall not be used if the type
+            // defined by "Type" is an untagged choice type or an 
+            // untagged open type'
+            throw new IllegalArgumentException(
+                    Messages.getString("security.9F")); //$NON-NLS-1$
+        }
+
+        this.type = type;
+
+        if (type.checkTag(type.id)) {
+            if (type.checkTag(type.constrId)) {
+                // the base encoding can be primitive ot constructed
+                // use both encodings
+                taggingType = TAGGING_STRING;
+            } else {
+                // if the base encoding is primitive use primitive encoding
+                taggingType = TAGGING_PRIMITIVE;
+            }
+        } else {
+            // if the base encoding is constructed use constructed encoding
+            taggingType = TAGGING_CONSTRUCTED;
+        }
+    }
+
+    //
+    //
+    // Decode
+    //
+    //
+
+    /**
+     * TODO
+     */
+    public final boolean checkTag(int identifier) {
+        switch (taggingType) {
+        case TAGGING_PRIMITIVE:
+            return id == identifier;
+        case TAGGING_CONSTRUCTED:
+            return constrId == identifier;
+        default: // TAGGING_STRING
+            return id == identifier || constrId == identifier;
+        }
+    }
+
+    /**
+     * TODO
+     */
+    public Object decode(BerInputStream in) throws IOException {
+        if (!checkTag(in.tag)) {
+            // FIXME need look for tagging type
+            throw new ASN1Exception(Messages.getString("security.100", //$NON-NLS-1$
+                    new Object[] { in.tagOffset, Integer.toHexString(id),
+                            Integer.toHexString(in.tag) }));
+        }
+
+        // substitute indentifier for further decoding
+        if (id == in.tag) {
+            in.tag = type.id;
+        } else {
+            in.tag = type.constrId;
+        }
+        in.content = type.decode(in);
+
+        if (in.isVerify) {
+            return null;
+        }
+        return getDecodedObject(in);
+    }
+
+    //
+    //
+    // Encode
+    //
+    //
+
+    public void encodeASN(BerOutputStream out) {
+        //FIXME need another way for specifying identifier to be encoded
+        if (taggingType == TAGGING_CONSTRUCTED) {
+            out.encodeTag(constrId);
+        } else {
+            out.encodeTag(id);
+        }
+        encodeContent(out);
+    }
+
+    public void encodeContent(BerOutputStream out) {
+        type.encodeContent(out);
+    }
+
+    public void setEncodingContent(BerOutputStream out) {
+        type.setEncodingContent(out);
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Integer.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Integer.java
new file mode 100644
index 0000000..95a2128
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Integer.java
@@ -0,0 +1,140 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+
+/**
+ * This class represents ASN.1 Integer type.
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public class ASN1Integer extends ASN1Primitive {
+
+    // default implementation
+    private static final ASN1Integer ASN1 = new ASN1Integer();
+
+    /**
+     * Constructs ASN.1 Integer type
+     * 
+     * The constructor is provided for inheritance purposes
+     * when there is a need to create a custom ASN.1 Integer type.
+     * To get a default implementation it is recommended to use
+     * getInstance() method.
+     */
+    public ASN1Integer() {
+        super(TAG_INTEGER);
+    }
+
+    /**
+     * Returns ASN.1 Integer type default implementation
+     * 
+     * The default implementation works with encoding
+     * that is represented as byte array in two's-complement notation.
+     *
+     * @return ASN.1 Integer type default implementation
+     */
+    public static ASN1Integer getInstance() {
+        return ASN1;
+    }
+
+    //
+    //
+    // Decode
+    //
+    //
+
+    public Object decode(BerInputStream in) throws IOException {
+        in.readInteger();
+
+        if (in.isVerify) {
+            return null;
+        }
+        return getDecodedObject(in);
+    }
+
+    /**
+     * Extracts array of bytes from BER input stream.
+     *
+     * @param in - BER input stream
+     * @return array of bytes
+     */
+    public Object getDecodedObject(BerInputStream in) throws IOException {
+        byte[] bytesEncoded = new byte[in.length];
+        System.arraycopy(in.buffer, in.contentOffset, bytesEncoded, 0,
+                in.length);
+        return bytesEncoded;
+    }
+
+    //
+    //
+    // Encode
+    //
+    //
+
+    public void encodeContent(BerOutputStream out) {
+        out.encodeInteger();
+    }
+
+    public void setEncodingContent(BerOutputStream out) {
+        out.length = ((byte[]) out.content).length;
+    }
+
+// BEGIN android-changed
+    /**
+     * Converts decoded ASN.1 Integer to int value.
+     * If the object represents an integer value
+     * larger than 32 bits, the high bits will be lost.
+     *
+     * @param decoded a decoded object corresponding to this type
+     * @return decoded int value.
+     */
+    public static int toIntValue(Object decoded) {
+        return new BigInteger((byte[]) decoded).intValue();//FIXME optimize
+    }
+
+    /**
+     * Converts decoded ASN.1 Integer to a BigInteger.
+     *
+     * @param decoded a decoded object corresponding to this type
+     * @return decoded BigInteger value.
+     */
+    public static BigInteger toBigIntegerValue(Object decoded) {
+        return new BigInteger((byte[]) decoded);//FIXME optimize
+    }
+// END android-changed
+
+    /**
+     * Converts primitive int value to a form most suitable for encoding.
+     *
+     * @param value primitive value to be encoded
+     * @return object suitable for encoding
+     */
+    public static Object fromIntValue(int value) {
+        //FIXME optimize
+        return BigInteger.valueOf(value).toByteArray();
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1OctetString.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1OctetString.java
new file mode 100644
index 0000000..90abd39
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1OctetString.java
@@ -0,0 +1,104 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.io.IOException;
+
+
+/**
+ * This class represents ASN.1 octet string type.
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public class ASN1OctetString extends ASN1StringType {
+
+    // default implementation
+    private static final ASN1OctetString ASN1 = new ASN1OctetString();
+
+    /**
+     * Constructs ASN.1 octet string type
+     * 
+     * The constructor is provided for inheritance purposes
+     * when there is a need to create a custom ASN.1 octet string type.
+     * To get a default implementation it is recommended to use
+     * getInstance() method.
+     */
+    public ASN1OctetString() {
+        super(TAG_OCTETSTRING);
+    }
+
+    /**
+     * Returns ASN.1 octet string type default implementation
+     * 
+     * The default implementation works with encoding
+     * that is represented as byte array.
+     *
+     * @return ASN.1 octet string type default implementation
+     */
+    public static ASN1OctetString getInstance() {
+        return ASN1;
+    }
+
+    //
+    //
+    // Decode
+    //
+    //
+
+    public Object decode(BerInputStream in) throws IOException {
+        in.readOctetString();
+
+        if (in.isVerify) {
+            return null;
+        }
+        return getDecodedObject(in);
+    }
+
+    /**
+     * Extracts array of bytes from BER input stream.
+     *
+     * @param in - BER input stream
+     * @return array of bytes
+     */
+    public Object getDecodedObject(BerInputStream in) throws IOException {
+        byte[] bytesEncoded = new byte[in.length];
+        System.arraycopy(in.buffer, in.contentOffset, bytesEncoded, 0,
+                in.length);
+        return bytesEncoded;
+    }
+
+    //
+    //
+    // Encode
+    //
+    //
+
+    public void encodeContent(BerOutputStream out) {
+        out.encodeOctetString();
+    }
+
+    public void setEncodingContent(BerOutputStream out) {
+        out.length = ((byte[]) out.content).length;
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Oid.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Oid.java
new file mode 100644
index 0000000..6292870
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Oid.java
@@ -0,0 +1,222 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.io.IOException;
+
+
+/**
+ * This class represents ASN.1 Object Identifier type.
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public class ASN1Oid extends ASN1Primitive {
+
+    // default implementation
+    private static final ASN1Oid ASN1 = new ASN1Oid();
+
+    /**
+     * Constructs ASN.1 Object Identifier type
+     * 
+     * The constructor is provided for inheritance purposes
+     * when there is a need to create a custom ASN.1 Object Identifier type.
+     * To get a default implementation it is recommended to use
+     * getInstance() method.
+     */
+    public ASN1Oid() {
+        super(TAG_OID);
+    }
+
+    /**
+     * Returns ASN.1 Object Identifier type default implementation
+     * 
+     * The default implementation works with encoding
+     * that is represented as array of integers.
+     *
+     * @return ASN.1 Object Identifier type default implementation
+     */
+    public static ASN1Oid getInstance() {
+        return ASN1;
+    }
+
+    //
+    //
+    // Decode
+    //
+    //
+
+    public Object decode(BerInputStream in) throws IOException {
+        in.readOID();
+
+        if (in.isVerify) {
+            return null;
+        }
+        return getDecodedObject(in);
+    }
+
+    /**
+     * Extracts array of integers from BER input stream.
+     *
+     * @param in - BER input stream
+     * @return array of integers
+     */
+    public Object getDecodedObject(BerInputStream in) throws IOException {
+        // Allocate and decode
+        int oidElement = in.oidElement;
+        int[] oid = new int[oidElement];
+        for (int id = 1, i = 0; id < oid.length; id++, i++) {
+            int octet = in.buffer[in.contentOffset + i];
+            oidElement = octet & 0x7F;
+            while ((octet & 0x80) != 0) {
+                i++;
+                octet = in.buffer[in.contentOffset + i];
+                oidElement = oidElement << 7 | (octet & 0x7f);
+            }
+            oid[id] = oidElement;
+        }
+        // Special handling for the first packed OID element
+        if (oid[1] > 79) {
+            oid[0] = 2;
+            oid[1] = oid[1] - 80;
+        } else {
+            oid[0] = oid[1] / 40;
+            oid[1] = oid[1] % 40;
+        }
+        return oid;
+    }
+
+    //
+    //
+    // Encode
+    //
+    //
+
+    public void encodeContent(BerOutputStream out) {
+        out.encodeOID();
+    }
+
+    public void setEncodingContent(BerOutputStream out) {
+        int[] oid = (int[]) out.content;
+
+        int length = 0;
+
+        // first subidentifier
+        int elem = oid[0] * 40 + oid[1];
+        if (elem == 0) {
+            length = 1;
+        } else {
+            for (; elem > 0; elem = elem >> 7) {
+                length++;
+            }
+        }
+
+        // the rest of subidentifiers
+        for (int i = 2; i < oid.length; i++) {
+            if (oid[i] == 0) {
+                length++;
+                continue;
+            }
+            for (elem = oid[i]; elem > 0; elem = elem >> 7) {
+                length++;
+            }
+        }
+        out.length = length;
+    }
+
+    //
+    //
+    // OID encoder/decoder for mapping to string 
+    //
+    //
+
+    private final static ASN1Oid STRING_OID = new ASN1Oid() {
+
+        public Object getDecodedObject(BerInputStream in) throws IOException {
+
+            StringBuffer buf = new StringBuffer();
+
+            int element;
+
+            //Special handling for the first packed OID element
+            int octet = in.buffer[in.contentOffset];
+            element = octet & 0x7F;
+
+            int index = 0;
+            while ((octet & 0x80) != 0) {
+                index++;
+                octet = in.buffer[in.contentOffset + index];
+                element = element << 7 | (octet & 0x7F);
+            }
+
+            if (element > 79) {
+                buf.append('2');
+                buf.append('.');
+                buf.append(element - 80);
+            } else {
+                buf.append(element / 40);
+                buf.append('.');
+                buf.append(element % 40);
+            }
+
+            // the rest of subidentifiers
+            for (int j = 2; j < in.oidElement; j++) {
+                buf.append('.');
+
+                index++;
+                octet = in.buffer[in.contentOffset + index];
+                element = octet & 0x7F;
+
+                while ((octet & 0x80) != 0) {
+                    index++;
+                    octet = in.buffer[in.contentOffset + index];
+                    element = element << 7 | (octet & 0x7f);
+                }
+
+                buf.append(element);
+            }
+
+            return buf.toString();
+        }
+
+        public void setEncodingContent(BerOutputStream out) {
+
+            //FIXME this is a stub for a while
+            out.content = ObjectIdentifier.toIntArray((String) out.content);
+
+            super.setEncodingContent(out);
+        }
+    };
+
+    /**
+     * Returns ASN.1 Object Identifier type implementation
+     * 
+     * This implementation works with encoding
+     * that is mapped to java.lang.String object.
+     *
+     * @return ASN.1 Object Identifier type implementation
+     */
+    public static ASN1Oid getInstanceForString() {
+        return STRING_OID;
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1OpenType.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1OpenType.java
new file mode 100644
index 0000000..0f8d9f6
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1OpenType.java
@@ -0,0 +1,85 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.io.IOException;
+
+import org.apache.harmony.security.x501.AttributeType;
+
+
+
+/**
+ * Represents ASN.1 open type that is defined by Oid
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public class ASN1OpenType extends ASN1Any {
+
+    private final Id key;
+
+    private final InformationObjectSet pool;
+
+    public ASN1OpenType(Id key, InformationObjectSet pool) {
+        this.key = key;
+        this.pool = pool;
+    }
+
+    public Object decode(BerInputStream in) throws IOException {
+
+        int[] oid = (int[]) in.get(key);
+        if (oid == null) {
+            throw new RuntimeException("");//FIXME message & type //$NON-NLS-1$
+        }
+
+        AttributeType attr = (AttributeType) pool.get(oid);
+        if (attr == null || (!attr.type.checkTag(in.tag))) {
+            in.content = (byte[]) super.getDecodedObject(in);
+        } else {
+            in.content = attr.type.decode(in);
+        }
+        return in.content;
+    }
+
+    public Object getDecodedObject(BerInputStream in) throws IOException {
+        return in.content;
+    }
+
+    public static class Id extends ASN1Oid {
+
+        public Object decode(BerInputStream in) throws IOException {
+            Object oid = super.decode(in);
+
+            if (oid == null) {
+                in.put(this, super.getDecodedObject(in));
+            } else {
+                in.put(this, oid);
+            }
+            return oid;
+        }
+
+        public Object getDecodedObject(BerInputStream in) throws IOException {
+            return in.get(this);
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Primitive.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Primitive.java
new file mode 100644
index 0000000..027c636
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Primitive.java
@@ -0,0 +1,57 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+
+/**
+ * This abstract class is the super class for all primitive ASN.1 types
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public abstract class ASN1Primitive extends ASN1Type {
+
+    public ASN1Primitive(int tagNumber) {
+        super(tagNumber);
+    }
+    
+    /**
+     * Tests provided identifier.
+     * 
+     * @param identifier -
+     *            identifier to be verified
+     * @return - true if identifier correspond to primitive identifier of this
+     *         ASN.1 type, otherwise false
+     */
+    public final boolean checkTag(int identifier) {
+        return this.id == identifier;
+    }
+    
+    /**
+     * TODO
+     */
+    public void encodeASN(BerOutputStream out) {
+        out.encodeTag(id);
+        encodeContent(out);
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Sequence.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Sequence.java
new file mode 100644
index 0000000..dbb59bf
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Sequence.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.io.IOException;
+
+
+/**
+ * This class represents ASN.1 Sequence type.
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public class ASN1Sequence extends ASN1TypeCollection {
+
+    public ASN1Sequence(ASN1Type[] type) {
+        super(TAG_SEQUENCE, type);
+
+        //FIXME optional components must be checked for distinct identifiers
+    }
+
+    //
+    //
+    // Decode
+    //
+    //
+
+    public Object decode(BerInputStream in) throws IOException {
+        in.readSequence(this);
+
+        if (in.isVerify) {
+            return null;
+        }
+        return getDecodedObject(in);
+    }
+
+    //
+    //
+    // Encode
+    //
+    //
+    public final void encodeContent(BerOutputStream out) {
+        out.encodeSequence(this);
+    }
+
+    public final void setEncodingContent(BerOutputStream out) {
+        out.getSequenceLength(this);
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1SequenceOf.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1SequenceOf.java
new file mode 100644
index 0000000..b9f1735
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1SequenceOf.java
@@ -0,0 +1,94 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+
+/**
+ * This class represents ASN.1 Sequence OF type.
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public class ASN1SequenceOf extends ASN1ValueCollection {
+
+    public ASN1SequenceOf(ASN1Type type) {
+        super(TAG_SEQUENCE, type);
+    }
+
+    //
+    //
+    // Decode
+    //
+    //
+
+    public Object decode(BerInputStream in) throws IOException {
+        in.readSequenceOf(this);
+
+        if (in.isVerify) {
+            return null;
+        }
+        return getDecodedObject(in);
+    }
+
+    //
+    //
+    // Encode
+    //
+    //
+
+    public final void encodeContent(BerOutputStream out) {
+        out.encodeSequenceOf(this);
+    }
+
+    public final void setEncodingContent(BerOutputStream out) {
+        out.getSequenceOfLength(this);
+    }
+
+    /**
+     * Creates array wrapper of provided ASN1 type
+     *
+     * @param type - ASN1 type to be wrapped
+     * @return - a wrapper for ASN1 set of type. 
+     * @throws IOException
+     * @see org.apache.harmony.security.asn1.ASN1ValueCollection
+     */
+    public static ASN1SequenceOf asArrayOf(ASN1Type type) {
+
+        return new ASN1SequenceOf(type) {
+            public Object getDecodedObject(BerInputStream in)
+                    throws IOException {
+                return ((List) in.content).toArray();
+            }
+
+            public Collection getValues(Object object) {
+                return Arrays.asList((Object[]) object);
+            }
+        };
+    }
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Set.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Set.java
new file mode 100644
index 0000000..5388434
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Set.java
@@ -0,0 +1,72 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.io.IOException;
+
+
+/**
+ * This class represents ASN.1 Set type.
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public class ASN1Set extends ASN1TypeCollection {
+
+    public ASN1Set(ASN1Type[] type) {
+        super(TAG_SET, type);
+
+        //FIXME implement check for distinct tags
+        //if (!hasDistinctTags(type)) {
+        //    throw new RuntimeException("ASN1 set type: " + getClass().getName()
+        //            + " MUST have alternatives with distinct tags");
+        //}
+    }
+
+    //
+    //
+    // Decode
+    //
+
+    public Object decode(BerInputStream in) throws IOException {
+        in.readSet(this);
+        
+        if(in.isVerify){
+            return null;
+        }
+        return getDecodedObject(in);
+    }
+
+    //
+    //
+    // Encode
+    //
+    //
+    public final void encodeContent(BerOutputStream out) {
+        out.encodeSet(this);
+    }
+
+    public final void setEncodingContent(BerOutputStream out) {
+        out.getSetLength(this);
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1SetOf.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1SetOf.java
new file mode 100644
index 0000000..b60c993
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1SetOf.java
@@ -0,0 +1,92 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+
+/**
+ * This class represents ASN.1 SetOf type.
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public class ASN1SetOf extends ASN1ValueCollection {
+
+    public ASN1SetOf(ASN1Type type) {
+        super(TAG_SETOF, type);
+    }
+
+    //
+    //
+    // Decode
+    //
+
+    public Object decode(BerInputStream in) throws IOException {
+        in.readSetOf(this);
+
+        if (in.isVerify) {
+            return null;
+        }
+        return getDecodedObject(in);
+    }
+
+    //
+    //
+    // Encode
+    //
+    //
+    public final void encodeContent(BerOutputStream out) {
+        out.encodeSetOf(this);
+    }
+
+    public final void setEncodingContent(BerOutputStream out) {
+        out.getSetOfLength(this);
+    }
+
+    /**
+     * Creates array wrapper of provided ASN1 type
+     *
+     * @param type - ASN1 type to be wrapped
+     * @return - a wrapper for ASN1 set of type. 
+     * @throws IOException
+     * @see org.apache.harmony.security.asn1.ASN1ValueCollection
+     */
+    public static ASN1SetOf asArrayOf(ASN1Type type) throws IOException {
+
+        return new ASN1SetOf(type) {
+            public Object getDecodedObject(BerInputStream in)
+                    throws IOException {
+                return ((List) in.content).toArray();
+            }
+
+            public Collection getValues(Object object) {
+                return Arrays.asList((Object[]) object);
+            }
+        };
+    }
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1StringType.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1StringType.java
new file mode 100644
index 0000000..55f48fa
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1StringType.java
@@ -0,0 +1,147 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+
+
+/**
+ * This class is the super class for all string ASN.1 types
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public abstract class ASN1StringType extends ASN1Type {
+
+    // TODO: what about defining them as separate classes?  
+    // TODO: check decoded/encoded characters
+    public static final ASN1StringType BMPSTRING = new ASN1StringType(
+            TAG_BMPSTRING) {
+    };
+
+    public static final ASN1StringType IA5STRING = new ASN1StringType(
+            TAG_IA5STRING) {
+    };
+
+    public static final ASN1StringType GENERALSTRING = new ASN1StringType(
+            TAG_GENERALSTRING) {
+    };
+
+    public static final ASN1StringType PRINTABLESTRING = new ASN1StringType(
+            TAG_PRINTABLESTRING) {
+    };
+
+    public static final ASN1StringType TELETEXSTRING = new ASN1StringType(
+            TAG_TELETEXSTRING) {
+    };
+
+    public static final ASN1StringType UNIVERSALSTRING = new ASN1StringType(
+            TAG_UNIVERSALSTRING) {
+    };
+
+    public static final ASN1StringType UTF8STRING = new ASN1StringType(
+            TAG_UTF8STRING) {
+
+        public Object getDecodedObject(BerInputStream in) throws IOException {
+            return new String(in.buffer, in.contentOffset, in.length, "UTF-8"); //$NON-NLS-1$
+        }
+
+        public void setEncodingContent(BerOutputStream out) {
+
+            try {
+                byte[] bytes = ((String) out.content).getBytes("UTF-8"); //$NON-NLS-1$
+                out.content = bytes;
+                out.length = bytes.length;
+            } catch (UnsupportedEncodingException e) {
+                throw new RuntimeException(e.getMessage());
+            }
+        }
+    };
+
+    public ASN1StringType(int tagNumber) {
+        super(tagNumber);
+    }
+
+    //
+    //
+    // Decode
+    //
+    //
+
+    /**
+     * Tests provided identifier.
+     * 
+     * @param identifier -
+     *            identifier to be verified
+     * @return - true if identifier correspond to primitive or constructed
+     *         identifier of this ASN.1 string type, otherwise false
+     */
+    public final boolean checkTag(int identifier) {
+        return this.id == identifier || this.constrId == identifier;
+    }
+
+    public Object decode(BerInputStream in) throws IOException {
+
+        in.readString(this);
+        
+        if (in.isVerify) {
+            return null;
+        }
+        return getDecodedObject(in);
+    }
+
+    /**
+     * Extracts String object from BER input stream.
+     *
+     * @param in - BER input stream
+     * @return java.land.String object
+     */
+    public Object getDecodedObject(BerInputStream in) throws IOException {
+        return new String(in.buffer, in.contentOffset, in.length);
+    }
+
+    //
+    //
+    // Encode
+    //
+    //
+    
+    public void encodeASN(BerOutputStream out) {
+        out.encodeTag(id);
+        encodeContent(out);
+    }
+
+    public void encodeContent(BerOutputStream out) {
+        out.encodeString();
+    }
+
+    public void setEncodingContent(BerOutputStream out) {
+
+        byte[] bytes = ((String) out.content).getBytes();
+
+        out.content = bytes;
+        out.length = bytes.length;
+    }
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Time.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Time.java
new file mode 100644
index 0000000..6fd930f
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Time.java
@@ -0,0 +1,64 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+
+/**
+ * Abstract class to represent ASN.1 time types
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public abstract class ASN1Time extends ASN1StringType {
+
+    /**
+     * TODO Put ctor description here
+     * 
+     * @param tagNumber
+     */
+    public ASN1Time(int tagNumber) {
+        super(tagNumber);
+    }
+
+    public Object getDecodedObject(BerInputStream in) throws IOException {
+        
+        // TODO optimize me:
+        // It makes sense use calendar instance instead of times array
+        GregorianCalendar c = new GregorianCalendar(TimeZone.getTimeZone("GMT")); //$NON-NLS-1$
+        
+        c.set(Calendar.YEAR, in.times[0]);
+        c.set(Calendar.MONTH, in.times[1]-1);
+        c.set(Calendar.DAY_OF_MONTH, in.times[2]);
+        c.set(Calendar.HOUR_OF_DAY, in.times[3]);
+        c.set(Calendar.MINUTE, in.times[4]);
+        c.set(Calendar.SECOND, in.times[5]);
+        c.set(Calendar.MILLISECOND, in.times[6]);
+        
+        return c.getTime();
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Type.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Type.java
new file mode 100644
index 0000000..8906bb7
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1Type.java
@@ -0,0 +1,214 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * This abstract class is the super class for all ASN.1 types
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public abstract class ASN1Type implements ASN1Constants {
+
+    /**
+     * Integer representation of primitive identifier.
+     */
+    public final int id;
+
+    /**
+     * Integer representation of constructed identifier.
+     */
+    public final int constrId;
+
+    /**
+     * Constructs a primitive, universal ASN.1 type.
+     * 
+     * @param tagNumber - ASN.1 tag number
+     * @throws IllegalArgumentException - if tagNumber is invalid
+     */
+    public ASN1Type(int tagNumber) {
+        this(CLASS_UNIVERSAL, tagNumber);
+    }
+
+    /**
+     * Constructs an ASN.1 type.
+     * 
+     * @param tagClass - tag class. MUST be
+     *     CLASS_UNIVERSAL, CLASS_APPLICATION, CLASS_CONTEXTSPECIFIC, CLASS_PRIVATE
+     * @param isConstructed - is ASN.1 type is a constructed type.
+     * @param tagNumber - ASN.1 tag number.
+     * @throws IllegalArgumentException - if tagClass or tagNumber is invalid
+     */
+    public ASN1Type(int tagClass, int tagNumber) {
+
+        if (tagNumber < 0) {
+            throw new IllegalArgumentException(Messages.getString("security.102")); //$NON-NLS-1$
+        }
+
+        if (tagClass != CLASS_UNIVERSAL && tagClass != CLASS_APPLICATION
+                && tagClass != CLASS_CONTEXTSPECIFIC
+                && tagClass != CLASS_PRIVATE) {
+            throw new IllegalArgumentException(Messages.getString("security.103")); //$NON-NLS-1$
+        }
+
+        if (tagNumber < 31) {
+            // short form
+            this.id = tagClass + tagNumber;
+        } else {
+            // long form
+            throw new IllegalArgumentException(
+                    Messages.getString("security.104")); //$NON-NLS-1$
+        }
+        this.constrId = this.id + PC_CONSTRUCTED;
+    }
+
+    //
+    //
+    // Stubs for DER
+    //
+    //
+
+    public final Object decode(byte[] encoded) throws IOException {
+        return decode(new DerInputStream(encoded));
+    }
+
+    public final Object decode(byte[] encoded, int offset, int encodingLen)
+            throws IOException {
+        return decode(new DerInputStream(encoded, offset, encodingLen));
+    }
+
+    public final Object decode(InputStream in) throws IOException {
+        return decode(new DerInputStream(in));
+    }
+
+    public final void verify(byte[] encoded) throws IOException {
+        DerInputStream decoder = new DerInputStream(encoded);
+        decoder.setVerify();
+        decode(decoder);
+    }
+
+    public final void verify(InputStream in) throws IOException {
+        DerInputStream decoder = new DerInputStream(in);
+        decoder.setVerify();
+        decode(decoder);
+    }
+
+    public final byte[] encode(Object object) {
+
+        DerOutputStream out = new DerOutputStream(this, object);
+        return out.encoded;
+    }
+
+    //
+    //
+    // Decode
+    //
+    //
+
+    /**
+     * Decodes ASN.1 type.
+     * 
+     * @param in -
+     *            BER input stream
+     * @throws IOException -
+     *             if an I/O error occurs or the end of the stream is reached
+     */
+    public abstract Object decode(BerInputStream in) throws IOException;
+
+    /**
+     * Tests provided identifier.
+     * 
+     * @param identifier -
+     *            identifier to be verified
+     * @return - true if identifier is associated with this ASN.1 type,
+     *         otherwise false
+     */
+    public abstract boolean checkTag(int identifier);
+
+    /**
+     * Creates decoded object.
+     * 
+     * Derived classes should override this method to provide creation for a
+     * selected class of objects during decoding.
+     * 
+     * The default implementation returns an object created by decoding stream.
+     * 
+     * @param -
+     *            input stream
+     * @return - created object
+     */
+    //FIXME make me public
+    protected Object getDecodedObject(BerInputStream in) throws IOException {
+        return in.content;
+    }
+
+    //
+    //
+    // Encode
+    //
+    //
+
+    /**
+     * Encodes ASN.1 type.
+     *
+     * @param out - BER output stream
+     */
+    public abstract void encodeASN(BerOutputStream out);
+
+    public abstract void encodeContent(BerOutputStream out);
+
+    public abstract void setEncodingContent(BerOutputStream out);
+
+    public int getEncodedLength(BerOutputStream out) { //FIXME name
+
+        //tag length
+        int len = 1; //FIXME tag length = 1. what about long form?
+        //for (; tag > 0; tag = tag >> 8, len++);
+
+        // length length :-)
+        len++;
+        if (out.length > 127) {
+
+            len++;
+            for (int cur = out.length >> 8; cur > 0; len++) {
+                cur = cur >> 8;
+            }
+        }
+        len += out.length;
+
+        return len;
+    }
+
+    public String toString() {
+        // TODO decide whether this method is necessary
+        //FIXME fix performance
+        return this.getClass().getName() + "(tag: 0x" //$NON-NLS-1$
+                + Integer.toHexString(0xff & this.id) + ")"; //$NON-NLS-1$
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1TypeCollection.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1TypeCollection.java
new file mode 100644
index 0000000..acb5f04
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1TypeCollection.java
@@ -0,0 +1,98 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * This abstract class represents ASN.1 type that is a collection of ASN.1 types.
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public abstract class ASN1TypeCollection extends ASN1Constructured {
+
+    public final ASN1Type[] type; //TODO comment me
+
+    public final boolean[] OPTIONAL; //TODO comment me
+
+    public final Object[] DEFAULT; //TODO comment me
+
+    /**
+     * Constructs ASN.1 collection type.
+     * 
+     * @param tagNumber - ASN.1 tag number
+     * @param type - a collection of one or more ASN.1 types. 
+     * @throws IllegalArgumentException - if tagNumber is invalid
+     */
+    public ASN1TypeCollection(int tagNumber, ASN1Type[] type) {
+        super(tagNumber);
+        // FIXME what about empty sequence?
+        //        if (type.length == 0) {
+        //            throw new ASN1Exception("ASN1 collection type: "
+        //                    + getClass().getName()
+        //                    + " MUST have at least one component");
+        //        }
+
+        this.type = type;
+        this.OPTIONAL = new boolean[type.length];
+        this.DEFAULT = new Object[type.length];
+    }
+
+    /**
+     * Sets a collection component as optional
+     *
+     * @param index - an index of a component
+     */
+    protected final void setOptional(int index) {
+        OPTIONAL[index] = true;
+    }
+
+    /**
+     * Sets a default value for a collection component.
+     * The component also became an optional component.
+     *
+     * @param object - a component's default value
+     * @param index - an index of a component
+     */
+    protected final void setDefault(Object object, int index) {
+        OPTIONAL[index] = true;
+        DEFAULT[index] = object;
+    }
+
+    /**
+     * Provides an object's values to be encoded
+     * 
+     * Derived classes should override this method to provide
+     * encoding for a selected class of objects. 
+     * 
+     * The default implementation throws RuntimeException.
+     *
+     * @param object - an object to be encoded
+     * @param values - an array to store an object's values to be encoded
+     */
+    protected void getValues(Object object, Object[] values) {
+        throw new RuntimeException(Messages.getString("security.101", getClass().getName())); //$NON-NLS-1$
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1UTCTime.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1UTCTime.java
new file mode 100644
index 0000000..0dd7ae4
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1UTCTime.java
@@ -0,0 +1,124 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.TimeZone;
+
+
+/**
+ * This class represents ASN.1 UTCTime type
+ * 
+ * According to X.680 specification this type is defined as follows:
+ *     UTCTime ::= [UNIVERSAL 23] IMPLICIT VisibleString
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+public class ASN1UTCTime extends ASN1Time {
+
+    /**
+     * Length for the pattern: YYMMDDhhmm'Z'
+     */
+    public static final int UTC_HM = 11;
+
+    /**
+     * Length for the pattern: YYMMDDhhmmss'Z'
+     */
+    public static final int UTC_HMS = 13;
+
+    /**
+     * Length for the pattern: YYMMDDhhmm('+'/'-')hhmm
+     */
+    public static final int UTC_LOCAL_HM = 15;
+
+    /**
+     * Length for the pattern: YYMMDDhhmmss('+'/'-')hhmm
+     */
+    public static final int UTC_LOCAL_HMS = 17;
+
+    // default implementation
+    private static final ASN1UTCTime ASN1 = new ASN1UTCTime();
+
+    /**
+     * Constructs ASN.1 UTCTime type
+     * 
+     * The constructor is provided for inheritance purposes
+     * when there is a need to create a custom ASN.1 UTCTime type.
+     * To get a default implementation it is recommended to use
+     * getInstance() method.
+     */
+    public ASN1UTCTime() {
+        super(TAG_UTCTIME);
+    }
+
+    /**
+     * Returns ASN.1 UTCTime type default implementation
+     * 
+     * The default implementation works with encoding
+     * that is represented as Date object.
+     *
+     * @return ASN.1 UTCTime type default implementation
+     */
+    public static ASN1UTCTime getInstance() {
+        return ASN1;
+    }
+
+    //
+    //
+    // Decode
+    //
+    //
+
+    public Object decode(BerInputStream in) throws IOException {
+        in.readUTCTime();
+
+        if (in.isVerify) {
+            return null;
+        }
+        return getDecodedObject(in);
+    }
+
+    //
+    //
+    // Encode
+    //
+    //
+    public void encodeContent(BerOutputStream out) {
+        out.encodeUTCTime();
+    }
+
+    // FIXME support only one format for encoding, do we need others?
+    //
+    // According to X.680 coordinated universal time format:
+    // two digit year, seconds always presented,
+    // no fractional-seconds elements, 'Z' at the end
+    private final static String UTC_PATTERN = "yyMMddHHmmss'Z'"; //$NON-NLS-1$
+
+    public void setEncodingContent(BerOutputStream out) {
+        SimpleDateFormat sdf = new SimpleDateFormat(UTC_PATTERN);
+        sdf.setTimeZone(TimeZone.getTimeZone("UTC")); //$NON-NLS-1$
+        out.content = sdf.format(out.content).getBytes();
+        out.length = ((byte[]) out.content).length;
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1ValueCollection.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1ValueCollection.java
new file mode 100644
index 0000000..ebcfbce
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ASN1ValueCollection.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.util.Collection;
+
+
+/**
+ * This abstract class represents ASN.1 collection type.
+ * 
+ * The value for such type is a collection of zero or
+ * more occurrences of a provided type. 
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public abstract class ASN1ValueCollection extends ASN1Constructured {
+
+    /**
+     * A value collection of this ASN.1 type
+     */
+    public final ASN1Type type;
+
+    /**
+     * Constructs ASN1 collection type.
+     * 
+     * @param tagNumber - ASN.1 tag number
+     * @param type - ASN.1 type
+     */
+    public ASN1ValueCollection(int tagNumber, ASN1Type type) {
+        super(tagNumber);
+
+        this.type = type;
+    }
+
+    /**
+     * Provides an object's values to be encoded
+     * 
+     * Derived classes should override this method to provide
+     * encoding for a selected class of objects. 
+     * 
+     * @param - an object to be encoded
+     * @return - a collection of object's values to be encoded 
+     */
+    public Collection getValues(Object object) {
+        return (Collection)object;
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/BerInputStream.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/BerInputStream.java
new file mode 100644
index 0000000..68819b8
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/BerInputStream.java
@@ -0,0 +1,996 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Calendar;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * Decodes ASN.1 types encoded with BER (X.690)
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public class BerInputStream {
+
+    /**
+     * Associated <code>InputStream</code>
+     */
+    protected InputStream in;
+
+    /**
+     * Internal buffer for storing encoded array 
+     */
+    protected byte[] buffer;
+
+    /**
+     * The position in the buffer.
+     * 
+     * Next read must place data into the buffer from this offset
+     */
+    protected int offset = 0;
+
+    // The buffer increment size.
+    // Must be reasonable big to reallocate memory not to often.
+    // Primary is used for decoding indefinite length encoding
+    private static final int BUF_INCREASE_SIZE = 1024 * 16;
+
+    /**
+     * Indicates indefinite length of the current type 
+     */
+    protected static final int INDEFINIT_LENGTH = -1;
+
+    /**
+     * Creates stream for decoding.
+     * 
+     * @param encoded - bytes array to be decoded
+     * @throws IOException - if an error occurs
+     */
+    public BerInputStream(byte[] encoded) throws IOException {
+        this(encoded, 0, encoded.length);
+    }
+
+    /**
+     * Creates stream for decoding.
+     * 
+     * @param encoded -
+     *            bytes array to be decoded
+     * @param offset -
+     *            the encoding offset
+     * @param expectedLength -
+     *            expected length of full encoding, this includes identifier,
+     *            length an content octets
+     * @throws IOException -
+     *             if an error occurs
+     */
+    public BerInputStream(byte[] encoded, int offset, int expectedLength)
+            throws IOException {
+
+        this.buffer = encoded;
+        this.offset = offset;
+
+        next();
+
+        // compare expected and decoded length
+        if (length != INDEFINIT_LENGTH
+                && (offset + expectedLength) != (this.offset + this.length)) {
+            throw new ASN1Exception(Messages.getString("security.111")); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Creates stream for decoding.
+     * 
+     * Allocates initial buffer of default size
+     *  
+     * @param is associated <code>InputStream</code>
+     */
+    public BerInputStream(InputStream in) throws IOException {
+        this(in, BUF_INCREASE_SIZE);
+    }
+
+    /**
+     * Creates stream for decoding.
+     * 
+     * Allocates initial buffer of <code>initialSize</code> size 
+     * 
+     * @param initialSize the internal buffer initial size
+     * @param is associated <code>InputStream</code>
+     */
+    public BerInputStream(InputStream in, int initialSize) throws IOException {
+
+        this.in = in;
+        buffer = new byte[initialSize];
+
+        next();
+
+        if (length != INDEFINIT_LENGTH) {
+            // input stream has definite length encoding
+            // check allocated length to avoid further reallocations
+            if (buffer.length < length) {
+                byte[] newBuffer = new byte[length];
+                System.arraycopy(buffer, 0, newBuffer, 0, offset);
+                buffer = newBuffer;
+            }
+        } else {
+            isIndefinedLength = true;
+            throw new ASN1Exception(Messages.getString("security.112")); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Resets this stream to initial state.
+     * 
+     * @param encoded - a new bytes array to be decoded
+     * @throws IOException - if an error occurs
+     */
+    public final void reset(byte[] encoded) throws IOException {
+        buffer = encoded;
+
+        next();
+    }
+
+    /**
+     * Current decoded tag
+     */
+    public int tag;
+
+    /**
+     * Current decoded length
+     */
+    protected int length;
+
+    /**
+     * Current decoded content
+     */
+    public Object content;
+
+    /**
+     * Current decoded tag offset
+     */
+    protected int tagOffset;
+
+    /**
+     * Current decoded content offset
+     */
+    protected int contentOffset;
+
+    /**
+     * Decodes next encoded type.
+     * Initializes tag, length, tagOffset and contentOffset variables
+     *
+     * @return next decoded tag
+     * @throws IOException - if error occured
+     */
+    public int next() throws IOException {
+
+        tagOffset = offset;
+
+        // read tag
+        tag = read();
+
+        // read length
+        length = read();
+        if (length != 0x80) { // definite form
+            // long or short length form
+            if ((length & 0x80) != 0) { // long form
+                int numOctets = length & 0x7F;
+
+                if (numOctets > 5) {
+                    throw new ASN1Exception(Messages.getString("security.113", //$NON-NLS-1$
+                            tagOffset)); //FIXME message
+                }
+
+                // collect this value length
+                length = read();
+                for (int i = 1; i < numOctets; i++) {
+                    int ch = read();
+                    length = (length << 8) + ch;//read();
+                }
+
+                if (length > 0xFFFFFF) {
+                    throw new ASN1Exception(Messages.getString("security.113", //$NON-NLS-1$
+                            tagOffset)); //FIXME message
+                }
+            }
+        } else { //indefinite form
+            length = INDEFINIT_LENGTH;
+        }
+        contentOffset = offset;
+
+        return tag;
+    }
+
+    /**
+     * Returns the length of the encoding
+     */
+    public static int getLength(byte[] encoding) {
+        int length = encoding[1] & 0xFF;
+        int numOctets = 0;
+        if ((length & 0x80) != 0) { // long form
+            numOctets = length & 0x7F;
+
+            // collect this value length
+            length = encoding[2] & 0xFF;
+            for (int i = 3; i < numOctets + 2; i++) {
+                length = (length << 8) + (encoding[i] & 0xFF);
+            }
+        }
+        //    tag length long_form content
+        return 1 + 1 + numOctets + length;
+    }
+
+    /**
+     * Decodes ASN.1 bitstring type
+     * 
+     * @throws IOException - if error occured
+     */
+    public void readBitString() throws IOException {
+
+        if (tag == ASN1Constants.TAG_BITSTRING) {
+
+            if (length == 0) {
+                throw new ASN1Exception(
+                        Messages.getString("security.114", tagOffset)); //$NON-NLS-1$
+            }
+
+            readContent();
+
+            // content: check unused bits
+            if (buffer[contentOffset] > 7) {
+                throw new ASN1Exception(Messages.getString("security.115", //$NON-NLS-1$
+                        contentOffset));
+            }
+
+            if (length == 1 && buffer[contentOffset] != 0) {
+                throw new ASN1Exception(Messages.getString("security.116", //$NON-NLS-1$
+                        contentOffset));
+            }
+
+        } else if (tag == ASN1Constants.TAG_C_BITSTRING) {
+            throw new ASN1Exception(Messages.getString("security.117")); //$NON-NLS-1$
+        } else {
+            throw new ASN1Exception(
+                    Messages.getString("security.118", tagOffset, //$NON-NLS-1$
+                            Integer.toHexString(tag)));
+        }
+    }
+
+    /**
+     * Decodes ASN.1 Enumerated type
+     * 
+     * @throws IOException - if error occured
+     */
+    public void readEnumerated() throws IOException {
+
+        if (tag != ASN1Constants.TAG_ENUM) {
+            throw new ASN1Exception(
+                    Messages.getString("security.119", tagOffset, //$NON-NLS-1$
+                            Integer.toHexString(tag)));
+        }
+
+        //
+        // all checks are the same as for ASN.1 integer type
+        //
+
+        // check encoded length
+        if (length == 0) {
+            throw new ASN1Exception(Messages.getString("security.11A", tagOffset));//$NON-NLS-1$
+        }
+
+        readContent();
+
+        // check encoded content
+        if (length > 1) {
+
+            int bits = buffer[contentOffset] & 0xFF;
+            if (buffer[contentOffset + 1] < 0) {
+                bits += 0x100;
+            }
+
+            if (bits == 0 || bits == 0x1FF) {
+                throw new ASN1Exception(Messages.getString("security.11B", contentOffset)); //$NON-NLS-1$
+            }
+        }
+    }
+
+    /**
+     * Decodes ASN.1 boolean type
+     * 
+     * @throws IOException - if error occured
+     */
+    public void readBoolean() throws IOException {
+
+        if (tag != ASN1Constants.TAG_BOOLEAN) {
+            throw new ASN1Exception(Messages.getString("security.11C", //$NON-NLS-1$
+                    tagOffset, Integer.toHexString(tag)));
+        }
+
+        // check encoded length
+        if (length != 1) {
+            throw new ASN1Exception(Messages.getString("security.11D", tagOffset));//$NON-NLS-1$
+        }
+
+        readContent();
+    }
+
+    /**
+     * The last choice index
+     */
+    public int choiceIndex;
+
+    /**
+     * Keeps last decoded: year, month, day, hour, minute, second, millisecond
+     */
+    public int[] times;
+
+    /**
+     * Decodes ASN.1 GeneralizedTime type
+     * 
+     * @throws IOException - if error occured
+     */
+    public void readGeneralizedTime() throws IOException {
+        
+        if (tag == ASN1Constants.TAG_GENERALIZEDTIME) {
+
+            // FIXME: any other optimizations?
+            readContent();
+            // FIXME store string somewhere to allow a custom time type perform
+            // additional checks
+
+            // check syntax: the last char MUST be Z
+            if (buffer[offset - 1] != 'Z') {
+                // FIXME support only format that is acceptable for DER
+                throw new ASN1Exception(Messages.getString("security.11E")); //$NON-NLS-1$
+            }
+
+            // check syntax: MUST be YYYYMMDDHHMMSS[(./,)DDD]'Z'
+            if (length != 15 && (length < 17 || length > 19)) // invalid
+                                                                // length
+            {
+                throw new ASN1Exception(Messages.getString("security.11F", //$NON-NLS-1$
+                                contentOffset));
+            }
+
+            // check content: milliseconds
+            if (length > 16) {
+                byte char14 = buffer[contentOffset + 14];
+                if (char14 != '.' && char14 != ',') {
+                    throw new ASN1Exception(
+                            Messages.getString("security.11F", //$NON-NLS-1$
+                                    contentOffset));
+                }
+            }
+
+            if (times == null) {
+                times = new int[7];
+            }
+            times[0] = strToInt(contentOffset, 4); // year
+            times[1] = strToInt(contentOffset + 4, 2); // month
+            times[2] = strToInt(contentOffset + 6, 2); // day
+            times[3] = strToInt(contentOffset + 8, 2); // hour
+            times[4] = strToInt(contentOffset + 10, 2); // minute
+            times[5] = strToInt(contentOffset + 12, 2); // second
+
+            if (length > 16) {
+                // FIXME optimize me
+                times[6] = strToInt(contentOffset + 15, length - 16);
+
+                if (length == 17) {
+                    times[6] = times[6] * 100;
+                } else if (length == 18) {
+                    times[6] = times[6] * 10;
+                }
+            }
+
+            // FIXME check all values for valid numbers!!!
+        } else if (tag == ASN1Constants.TAG_C_GENERALIZEDTIME) {
+            throw new ASN1Exception(Messages.getString("security.120")); //$NON-NLS-1$
+
+        } else {
+            throw new ASN1Exception(Messages.getString("security.121", //$NON-NLS-1$
+                            tagOffset, Integer.toHexString(tag)));
+        }
+    }
+
+    /**
+     * Decodes ASN.1 UTCTime type
+     *
+     * @throws IOException - if an I/O error occurs or the end of the stream is reached
+     */
+    public void readUTCTime() throws IOException {
+
+        if (tag == ASN1Constants.TAG_UTCTIME) {
+
+            switch (length) {
+            case ASN1UTCTime.UTC_HM:
+            case ASN1UTCTime.UTC_HMS:
+                break;
+            case ASN1UTCTime.UTC_LOCAL_HM:
+            case ASN1UTCTime.UTC_LOCAL_HMS:
+                // FIXME only coordinated universal time formats are supported
+                throw new ASN1Exception(Messages.getString("security.122")); //$NON-NLS-1$
+            default:
+                throw new ASN1Exception(Messages.getString("security.123", //$NON-NLS-1$
+                                tagOffset));
+            }
+
+            // FIXME: any other optimizations?
+            readContent();
+
+            // FIXME store string somewhere to allow a custom time type perform
+            // additional checks
+
+            // check syntax: the last char MUST be Z
+            if (buffer[offset - 1] != 'Z') {
+                throw new ASN1Exception("ASN.1 UTCTime wrongly encoded at [" //$NON-NLS-1$
+                        + contentOffset + ']');
+            }
+
+            if (times == null) {
+                times = new int[7];
+            }
+
+            times[0] = strToInt(contentOffset, 2); // year
+            if (times[0] > 49) {
+                times[0] += 1900;
+            } else {
+                times[0] += 2000;
+            }
+
+            times[1] = strToInt(contentOffset + 2, 2); // month
+            times[2] = strToInt(contentOffset + 4, 2); // day
+            times[3] = strToInt(contentOffset + 6, 2); // hour
+            times[4] = strToInt(contentOffset + 8, 2); // minute
+
+            if (length == ASN1UTCTime.UTC_HMS) {
+                times[5] = strToInt(contentOffset + 10, 2); // second
+            }
+
+            // FIXME check all time values for valid numbers!!!
+        } else if (tag == ASN1Constants.TAG_C_UTCTIME) {
+            throw new ASN1Exception(Messages.getString("security.124")); //$NON-NLS-1$
+        } else {
+            throw new ASN1Exception(Messages.getString("security.125", //$NON-NLS-1$
+                    tagOffset, Integer.toHexString(tag)));
+        }
+    }
+
+    //TODO comment me
+    private int strToInt(int off, int count) throws ASN1Exception {
+
+        //FIXME works only with buffer
+
+        int c;
+        int result = 0;
+        for (int i = off, end = off + count; i < end; i++) {
+            c = buffer[i] - 48;
+            if (c < 0 || c > 9) {
+                throw new ASN1Exception(Messages.getString("security.126")); //$NON-NLS-1$
+            }
+            result = result * 10 + c;
+        }
+        return result;
+    }
+
+    /**
+     * Decodes ASN.1 Integer type
+     * 
+     * @throws IOException - if error occured
+     */
+    public void readInteger() throws IOException {
+
+        if (tag != ASN1Constants.TAG_INTEGER) {
+            throw new ASN1Exception(Messages.getString("security.127", //$NON-NLS-1$
+                    tagOffset, Integer.toHexString(tag)));
+        }
+
+        // check encoded length
+        if (length < 1) {
+            throw new ASN1Exception(Messages.getString("security.128", //$NON-NLS-1$
+                    tagOffset)); //$NON-NLS-1$
+        }
+
+        readContent();
+
+        // check encoded content
+        if (length > 1) {
+
+            byte firstByte = buffer[offset - length];
+            byte secondByte = (byte) (buffer[offset - length + 1] & 0x80);
+
+            if (firstByte == 0 && secondByte == 0 || firstByte == (byte) 0xFF
+                    && secondByte == (byte) 0x80) {
+                throw new ASN1Exception(Messages.getString("security.129", //$NON-NLS-1$
+                                (offset - length)));
+            }
+        }
+    }
+
+    /**
+     * Decodes ASN.1 Octetstring type
+     *
+     * @throws IOException - if error occured
+     */
+    public void readOctetString() throws IOException {
+
+        if (tag == ASN1Constants.TAG_OCTETSTRING) {
+            readContent();
+        } else if (tag == ASN1Constants.TAG_C_OCTETSTRING) {
+            throw new ASN1Exception(Messages.getString("security.12A")); //$NON-NLS-1$
+        } else {
+            throw new ASN1Exception(
+                    Messages.getString("security.12B", tagOffset, //$NON-NLS-1$
+                            Integer.toHexString(tag)));
+        }
+    }
+
+    //FIXME comment me
+    public int oidElement;
+
+    /**
+     * Decodes ASN.1 ObjectIdentifier type
+     *
+     * @throws IOException - if error occured
+     */
+    public void readOID() throws IOException {
+
+        if (tag != ASN1Constants.TAG_OID) {
+            throw new ASN1Exception(Messages.getString("security.12C", //$NON-NLS-1$
+                    tagOffset, Integer.toHexString(tag)));
+        }
+
+        // check encoded length
+        if (length < 1) {
+            throw new ASN1Exception(Messages.getString("security.12D", tagOffset)); //$NON-NLS-1$
+        }
+
+        readContent();
+
+        // check content: last encoded byte (8th bit MUST be zero)
+        if ((buffer[offset - 1] & 0x80) != 0) {
+            throw new ASN1Exception(Messages.getString("security.12E", (offset - 1))); //$NON-NLS-1$
+        }
+
+        oidElement = 1;
+        for (int i = 0; i < length; i++, ++oidElement) {
+        
+            // According to ASN.1 BER spec:
+            //    leading octet of subidentifier MUST not be 0x80
+            // This assertion is not verified
+            //
+            //if (buffer[contentOffset + i] == (byte)0x80) {
+            //    throw new ASN1Exception(
+            //            "Wrong content for ASN.1 object identifier at ["
+            //                    + contentOffset
+            //                    + "]. Subidentifier MUST be encoded in minimum number of octets");
+            //}
+        
+            while ((buffer[contentOffset + i] & 0x80) == 0x80) {
+                i++;
+            }
+        }
+    }
+
+    /**
+     * Decodes ASN.1 Sequence type
+     *
+     * @param sequence - ASN.1 sequence to be decoded
+     * @throws IOException - if error occured
+     */
+    public void readSequence(ASN1Sequence sequence) throws IOException {
+
+        if (tag != ASN1Constants.TAG_C_SEQUENCE) {
+            throw new ASN1Exception(
+                    Messages.getString("security.12F", tagOffset, //$NON-NLS-1$
+                            Integer.toHexString(tag)));
+        }
+
+        int begOffset = offset;
+        int endOffset = begOffset + length;
+
+        ASN1Type[] type = sequence.type;
+
+        int i = 0;
+
+        if (isVerify) {
+
+            for (; (offset < endOffset) && (i < type.length); i++) {
+
+                next();
+                while (!type[i].checkTag(tag)) {
+                    // check whether it is optional component or not 
+                    if (!sequence.OPTIONAL[i] || (i == type.length - 1)) {
+                        throw new ASN1Exception(Messages.getString("security.130", //$NON-NLS-1$
+                                        tagOffset));
+                    }
+                    i++;
+                }
+
+                type[i].decode(this);
+            }
+
+            // check the rest of components
+            for (; i < type.length; i++) {
+                if (!sequence.OPTIONAL[i]) {
+                    throw new ASN1Exception(Messages.getString("security.131", //$NON-NLS-1$
+                            tagOffset));
+                }
+            }
+
+        } else {
+
+            int seqTagOffset = tagOffset; //store tag offset
+
+            Object[] values = new Object[type.length];
+            for (; (offset < endOffset) && (i < type.length); i++) {
+
+                next();
+                while (!type[i].checkTag(tag)) {
+                    // check whether it is optional component or not 
+                    if (!sequence.OPTIONAL[i] || (i == type.length - 1)) {
+                        throw new ASN1Exception(Messages.getString("security.132", //$NON-NLS-1$
+                                        tagOffset));
+                    }
+
+                    // sets default value
+                    if (sequence.DEFAULT[i] != null) {
+                        values[i] = sequence.DEFAULT[i];
+                    }
+                    i++;
+                }
+                values[i] = type[i].decode(this);
+            }
+
+            // check the rest of components
+            for (; i < type.length; i++) {
+                if (!sequence.OPTIONAL[i]) {
+                    throw new ASN1Exception(Messages.getString("security.133", //$NON-NLS-1$
+                            tagOffset));
+                }
+                if (sequence.DEFAULT[i] != null) {
+                    values[i] = sequence.DEFAULT[i];
+                }
+            }
+            content = values;
+
+            tagOffset = seqTagOffset; //retrieve tag offset
+        }
+
+        if (offset != endOffset) {
+            throw new ASN1Exception(Messages.getString("security.134", begOffset)); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Decodes ASN.1 SequenceOf type
+     *
+     * @param sequenceOf - ASN.1 sequence to be decoded
+     * @throws IOException - if error occured
+     */
+    public void readSequenceOf(ASN1SequenceOf sequenceOf) throws IOException {
+        
+        if (tag != ASN1Constants.TAG_C_SEQUENCEOF) {
+            throw new ASN1Exception(Messages.getString("security.135", tagOffset, //$NON-NLS-1$
+                            Integer.toHexString(tag)));
+        }
+
+        decodeValueCollection(sequenceOf);
+    }
+
+    /**
+     * Decodes ASN.1 Set type
+     *
+     * @param set - ASN.1 set to be decoded
+     * @throws IOException - if error occured
+     */
+    public void readSet(ASN1Set set) throws IOException {
+        
+        if (tag != ASN1Constants.TAG_C_SET) {
+            throw new ASN1Exception(Messages.getString("security.136", //$NON-NLS-1$
+                    tagOffset, Integer.toHexString(tag)));
+        }
+
+        throw new ASN1Exception(Messages.getString("security.137")); //$NON-NLS-1$
+    }
+
+    /**
+     * Decodes ASN.1 SetOf type
+     *
+     * @param set - ASN.1 set to be decoded
+     * @throws IOException - if error occured
+     */
+    public void readSetOf(ASN1SetOf setOf) throws IOException {
+        
+        if (tag != ASN1Constants.TAG_C_SETOF) {
+            throw new ASN1Exception(Messages.getString("security.138", //$NON-NLS-1$
+                    tagOffset, Integer.toHexString(tag)));
+        }
+
+        decodeValueCollection(setOf);
+    }
+
+    private final void decodeValueCollection(ASN1ValueCollection collection)
+            throws IOException {
+
+        int begOffset = offset;
+        int endOffset = begOffset + length;
+
+        ASN1Type type = collection.type;
+
+        if (isVerify) {
+            while (endOffset > offset) {
+                next();
+                type.decode(this);
+            }
+        } else {
+
+            int seqTagOffset = tagOffset; //store tag offset
+
+            ArrayList values = new ArrayList();
+            while (endOffset > offset) {
+                next();
+                values.add(type.decode(this));
+            }
+
+            content = values;
+
+            tagOffset = seqTagOffset; //retrieve tag offset
+        }
+
+        if (offset != endOffset) {
+            throw new ASN1Exception(Messages.getString("security.134", begOffset)); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Decodes ASN.1 String type
+     *
+     * @throws IOException - if an I/O error occurs or the end of the stream is reached
+     */
+    public void readString(ASN1StringType type) throws IOException {
+
+        //FIXME check string content
+        if (tag == type.id) {
+            readContent();
+        } else if (tag == type.constrId) {
+            throw new ASN1Exception(Messages.getString("security.139")); //$NON-NLS-1$
+        } else {
+            throw new ASN1Exception(
+                    Messages.getString("security.13A", tagOffset, //$NON-NLS-1$
+                            Integer.toHexString(tag)));
+        }
+    }
+
+    /**
+     * Returns encoded array.
+     * 
+     * MUST be invoked after decoding corresponding ASN.1 notation  
+     */
+    public byte[] getEncoded() {
+        byte[] encoded = new byte[offset - tagOffset];
+        System.arraycopy(buffer, tagOffset, encoded, 0, encoded.length);
+        return encoded;
+    }
+
+    /**
+     * Returns internal buffer used for decoding
+     *
+     * @return - buffer
+     */
+    public final byte[] getBuffer() {
+        return buffer;
+    }
+
+    /**
+     * Returns length of the current content for decoding
+     *
+     * @return - length of content
+     */
+    public final int getLength() {
+        return length;
+    }
+
+    /**
+     * Returns the current offset
+     *
+     * @return - offset
+     */
+    public final int getOffset() {
+        return offset;
+    }
+
+    /**
+     * Returns end offset for the current encoded type
+     *
+     * @return - offset
+     */
+    public final int getEndOffset() {
+        return offset + length;
+    }
+
+    /**
+     * Returns start offset for the current encoded type
+     *
+     * @return - offset
+     */
+    public final int getTagOffset() {
+        return tagOffset;
+    }
+
+    public final int getContentOffset() {
+        return contentOffset;
+    }
+
+    /**
+     * Indicates verify or store mode.
+     * 
+     * In store mode a decoded content is stored in a newly allocated
+     * appropriate object. The <code>content</code> variable holds
+     * a reference to the last created object.
+     * 
+     * In verify mode a decoded content is not stored.
+     */
+    // FIXME it is used only for one case
+    // decoding PCKS#8 Private Key Info notation
+    // remove this option because it does decoding more complex
+    protected boolean isVerify;
+
+    /**
+     * Sets verify mode.
+     */
+    public final void setVerify() {
+        isVerify = true;
+    }
+
+    /**
+     * Indicates defined or indefined reading mode for associated InputStream.
+     * 
+     * This mode is defined by reading a length
+     * for a first ASN.1 type from InputStream.
+     */
+    protected boolean isIndefinedLength;
+
+    /**
+     * Reads the next encoded byte from the encoded input stream.
+     *
+     * @return the next encoded byte
+     * @throws IOException - if error occured
+     */
+    protected int read() throws IOException {
+
+        if (offset == buffer.length) {
+            throw new ASN1Exception(Messages.getString("security.13B")); //$NON-NLS-1$
+        }
+
+        if (in == null) {
+            return buffer[offset++] & 0xFF;
+        } else {
+            int octet = in.read();
+            if (octet == -1) {
+                throw new ASN1Exception(Messages.getString("security.13B")); //$NON-NLS-1$
+            }
+            
+            buffer[offset++] = (byte) octet;
+            
+            return octet;
+        }
+    }
+
+    /**
+     * Reads the next encoded content from the encoded input stream.
+     * The method MUST be used for reading a primitive encoded content.
+     *
+     * @throws IOException - if error occured
+     */
+    public void readContent() throws IOException {
+        if (offset + length > buffer.length) {
+            throw new ASN1Exception(Messages.getString("security.13B")); //$NON-NLS-1$
+        }
+
+        if (in == null) {
+            offset += length;
+        } else {
+            if (in.read(buffer, offset, length) != length) {
+                throw new ASN1Exception(Messages.getString("security.13C")); //$NON-NLS-1$
+            }
+            offset += length;
+        }
+    }
+
+    //    // reallocates internal buffer for indefined reading mode
+    //    private void reallocateBuffer(int n) {
+    //        int newSize;
+    //        for (newSize = buffer.length * 2; newSize < buffer.length + n; newSize = newSize * 2)
+    //            ;
+    //        byte[] newBuffer = new byte[newSize];
+    //        System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
+    //        buffer = newBuffer;
+    //    }
+
+    /**
+     * Reallocates the buffer in order to make it
+     * exactly the size of data it contains
+     */
+    public void compactBuffer() {
+        if (offset != buffer.length) {
+            byte[] newBuffer = new byte[offset];
+            // restore buffer content
+            System.arraycopy(buffer, 0, newBuffer, 0, offset);
+            // set new buffer
+            buffer = newBuffer;
+        }
+    }
+
+    //
+    //
+    //
+    //
+    //
+
+    private Object[][] pool;
+
+    public void put(Object key, Object entry) {
+
+        if (pool == null) {
+            pool = new Object[2][10];
+        }
+
+        int i = 0;
+        for (; i < pool[0].length && pool[0][i] != null; i++) {
+            if (pool[0][i] == key) {
+                pool[1][i] = entry;
+                return;
+            }
+        }
+
+        if (i == pool[0].length) {
+            Object[][] newPool = new Object[pool[0].length * 2][2];
+            System.arraycopy(pool[0], 0, newPool[0], 0, pool[0].length);
+            System.arraycopy(pool[1], 0, newPool[1], 0, pool[0].length);
+            pool = newPool;
+        } else {
+            pool[0][i] = key;
+            pool[1][i] = entry;
+        }
+    }
+
+    public Object get(Object key) {
+
+        if (pool == null) {
+            return null;
+        }
+
+        for (int i = 0; i < pool[0].length; i++) {
+            if (pool[0][i] == key) {
+                return pool[1][i];
+            }
+        }
+        return null;
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/BerOutputStream.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/BerOutputStream.java
new file mode 100644
index 0000000..eb018fd
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/BerOutputStream.java
@@ -0,0 +1,224 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+
+/**
+ * Encodes ASN.1 types with BER (X.690)
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public class BerOutputStream {
+
+    /**
+     *  Encoded byte array
+     */
+    public byte[] encoded;
+
+    /**
+     *  current offset
+     */
+    protected int offset;
+
+    /**
+     * Current encoded length
+     */
+    public int length;
+
+    /**
+     * Current encoded content
+     */
+    public Object content;
+
+    public BerOutputStream() {
+    }
+
+    public final void encodeTag(int tag) {
+
+        encoded[offset++] = (byte) tag; //FIXME long form?
+
+        if (length > 127) { //long form
+            int eLen = length >> 8;
+            byte numOctets = 1;
+            for (; eLen > 0; eLen = eLen >> 8) {
+                numOctets++;
+            }
+
+            encoded[offset] = (byte) (numOctets | 0x80);
+            offset++;
+
+            eLen = length;
+            int numOffset = offset + numOctets - 1;
+            for (int i = 0; i < numOctets; i++, eLen = eLen >> 8) {
+                encoded[numOffset - i] = (byte) eLen; //FIXME long value?
+            }
+            offset += numOctets;
+        } else { //short form
+            encoded[offset++] = (byte) length;
+        }
+    }
+
+    public void encodeANY() {
+        System.arraycopy(content, 0, encoded, offset, length);
+        offset += length;
+    }
+
+    public void encodeBitString() {
+        //FIXME check encoding
+        BitString bStr = (BitString) content;
+        encoded[offset] = (byte) bStr.unusedBits;
+        System.arraycopy(bStr.bytes, 0, encoded, offset + 1, length - 1);
+        offset += length;
+    }
+
+    public void encodeBoolean() {
+        if (((Boolean) content).booleanValue()) {
+            encoded[offset] = (byte) 0xFF;
+        } else {
+            encoded[offset] = 0x00;
+        }
+        offset++;
+    }
+
+    public void encodeChoice(ASN1Choice choice) {
+        throw new RuntimeException("Is not implemented yet"); //FIXME
+    }
+
+    public void encodeExplicit(ASN1Explicit explicit) {
+        throw new RuntimeException("Is not implemented yet"); //FIXME
+    }
+
+    public void encodeGeneralizedTime() {
+        System.arraycopy(content, 0, encoded, offset, length);
+        offset += length;
+    }
+
+    public void encodeUTCTime() {
+        System.arraycopy(content, 0, encoded, offset, length);
+        offset += length;
+    }
+
+    public void encodeInteger() {
+        System.arraycopy(content, 0, encoded, offset, length);
+        offset += length;
+    }
+
+    public void encodeOctetString() {
+        System.arraycopy(content, 0, encoded, offset, length);
+        offset += length;
+    }
+
+    public void encodeOID() {
+
+        int[] oid = (int[]) content;
+
+        int oidLen = length;
+
+        // all subidentifiers except first
+        int elem;
+        for (int i = oid.length - 1; i > 1; i--, oidLen--) {
+            elem = oid[i];
+            if (elem > 127) {
+                encoded[offset + oidLen - 1] = (byte) (elem & 0x7F);
+                elem = elem >> 7;
+                for (; elem > 0;) {
+                    oidLen--;
+                    encoded[offset + oidLen - 1] = (byte) (elem | 0x80);
+                    elem = elem >> 7;
+                }
+            } else {
+                encoded[offset + oidLen - 1] = (byte) elem;
+            }
+        }
+
+        // first subidentifier
+        elem = oid[0] * 40 + oid[1];
+        if (elem > 127) {
+            encoded[offset + oidLen - 1] = (byte) (elem & 0x7F);
+            elem = elem >> 7;
+            for (; elem > 0;) {
+                oidLen--;
+                encoded[offset + oidLen - 1] = (byte) (elem | 0x80);
+                elem = elem >> 7;
+            }
+        } else {
+            encoded[offset + oidLen - 1] = (byte) elem;
+        }
+
+        offset += length;
+    }
+
+    public void encodeSequence(ASN1Sequence sequence) {
+        throw new RuntimeException("Is not implemented yet"); //FIXME
+    }
+
+    public void encodeSequenceOf(ASN1SequenceOf sequenceOf) {
+        throw new RuntimeException("Is not implemented yet"); //FIXME
+    }
+
+    public void encodeSet(ASN1Set set) {
+        throw new RuntimeException("Is not implemented yet"); //FIXME
+    }
+
+    public void encodeSetOf(ASN1SetOf setOf) {
+        throw new RuntimeException("Is not implemented yet"); //FIXME
+    }
+
+    public void encodeString() {
+        System.arraycopy(content, 0, encoded, offset, length);
+        offset += length;
+    }
+
+    /*
+     * LENGTH 
+     */
+
+    public void getChoiceLength(ASN1Choice choice) {
+        throw new RuntimeException("Is not implemented yet"); //FIXME
+    }
+
+    public void getExplicitLength(ASN1Explicit sequence) {
+        throw new RuntimeException("Is not implemented yet"); //FIXME
+    }
+
+    public void getSequenceLength(ASN1Sequence sequence) {
+        throw new RuntimeException("Is not implemented yet"); //FIXME
+    }
+
+    public void getSequenceOfLength(ASN1SequenceOf sequence) {
+        throw new RuntimeException("Is not implemented yet"); //FIXME
+    }
+
+    public void getSetLength(ASN1Set set) {
+        throw new RuntimeException("Is not implemented yet"); //FIXME
+    }
+
+    public void getSetOfLength(ASN1SetOf setOf) {
+        throw new RuntimeException("Is not implemented yet"); //FIXME
+    }
+
+    public int getStringLength(Object object) {
+        throw new RuntimeException("Is not implemented yet"); //FIXME
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/BitString.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/BitString.java
new file mode 100644
index 0000000..f0f4098
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/BitString.java
@@ -0,0 +1,116 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * Represents ASN.1 bit string value
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public final class BitString {
+
+    private static final byte[] SET_MASK = { (byte) 128, 64, 32, 16, 8, 4, 2, 1 };
+
+    private static final byte[] RESET_MASK = { 0x7f, (byte) 0xbf, (byte) 0xdf,
+            (byte) 0xef, (byte) 0xf7, (byte) 0xfb, (byte) 0xfd, (byte) 0xfe, };
+
+    /**
+     * Sequence of bits padded with unused bits.
+     * @see #unusedBits 
+     */
+    public final byte[] bytes;
+
+    /**
+     * Number of unused bits in the last byte.
+     */
+    public final int unusedBits;
+
+    /**
+     * Constructs bit string
+     * 
+     * @param bytes - array of bytes that represents bit string,
+     *                including unused bits
+     * @param unusedBits - number of unused bits
+     * @throws IllegalArgumentException - if parameters are invalid
+     */
+    public BitString(byte[] bytes, int unusedBits) {
+
+        // constraints are set according X.690
+        if (unusedBits < 0 || unusedBits > 7) {
+            throw new IllegalArgumentException(
+                    Messages.getString("security.13D")); //$NON-NLS-1$
+        }
+
+        if (bytes.length == 0 && unusedBits != 0) {
+            throw new IllegalArgumentException(
+                    Messages.getString("security.13E")); //$NON-NLS-1$
+        }
+
+        this.bytes = bytes;
+        this.unusedBits = unusedBits;
+    }
+
+    /**
+     * Constructs bit string from array of booleans
+     * 
+     * @param values - array of booleans
+     */
+    public BitString(boolean[] values) {
+        unusedBits = values.length % 8;
+        int size = values.length / 8;
+        if (unusedBits != 0) {
+            size++;
+        }
+        bytes = new byte[size];
+        for (int i = 0; i < values.length; i++) {
+            setBit(i, values[i]);
+        }
+    }
+
+    public boolean getBit(int bit) {
+        int offset = bit % 8;
+        int index = bit / 8;
+        return (bytes[index] & SET_MASK[offset]) != 0;
+    }
+
+    public void setBit(int bit, boolean value) {
+        int offset = bit % 8;
+        int index = bit / 8;
+        if (value) {
+            bytes[index] |= SET_MASK[offset];
+        } else {
+            bytes[index] &= RESET_MASK[offset];
+        }
+    }
+
+    public boolean[] toBooleanArray() {
+        boolean[] result = new boolean[bytes.length * 8 - unusedBits];
+        for (int i = 0; i < result.length; i++) {
+            result[i] = getBit(i);
+        }
+        return result;
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/DerInputStream.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/DerInputStream.java
new file mode 100644
index 0000000..01226b6
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/DerInputStream.java
@@ -0,0 +1,201 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * Decodes ASN.1 types encoded with DER (X.690)
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public final class DerInputStream extends BerInputStream {
+
+    public DerInputStream(byte[] encoded) throws IOException {
+        super(encoded, 0, encoded.length);
+    }
+
+    public DerInputStream(byte[] encoded, int offset, int encodingLen)
+            throws IOException {
+        super(encoded, offset, encodingLen);
+    }
+
+    public DerInputStream(InputStream in) throws IOException {
+        super(in);
+    }
+
+    /**
+     * @see org.apache.harmony.security.asn1.BerInputStream#next()
+     */
+    public final int next() throws IOException {
+
+        int tag = super.next();
+
+        if (length == INDEFINIT_LENGTH) {
+            throw new ASN1Exception(Messages.getString("security.105")); //$NON-NLS-1$
+        }
+
+        // FIXME add check: length encoding uses minimum number of octets
+
+        return tag;
+    }
+
+    // mask for verifying unused bits for ASN.1 bitstring
+    private static final byte[] UNUSED_BITS_MASK = new byte[] { 0x01, 0x03,
+            0x07, 0x0F, 0x1F, 0x3F, 0x7F };
+
+
+    /**
+     * @see org.apache.harmony.security.asn1.BerInputStream#readBitString()
+     */
+    public void readBitString() throws IOException {
+
+        if (tag == ASN1Constants.TAG_C_BITSTRING) {
+            throw new ASN1Exception(Messages.getString("security.106", tagOffset)); //$NON-NLS-1$
+        }
+
+        super.readBitString();
+
+        //check: unused bits values - MUST be 0
+        if (length > 1
+                && buffer[contentOffset] != 0
+                && (buffer[offset - 1] & UNUSED_BITS_MASK[buffer[contentOffset] - 1]) != 0) {
+            throw new ASN1Exception(Messages.getString("security.107", contentOffset)); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * @see org.apache.harmony.security.asn1.BerInputStream#readBoolean()
+     */
+    public void readBoolean() throws IOException {
+
+        super.readBoolean();
+
+        // check encoded content
+        if (buffer[contentOffset] != 0 && buffer[contentOffset] != (byte) 0xFF) {
+            throw new ASN1Exception(Messages.getString("security.108", contentOffset)); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * @see org.apache.harmony.security.asn1.BerInputStream#readOctetString()
+     */
+    public void readOctetString() throws IOException {
+
+        if (tag == ASN1Constants.TAG_C_OCTETSTRING) {
+            throw new ASN1Exception(
+                    Messages.getString("security.109", tagOffset)); //$NON-NLS-1$
+        }
+        super.readOctetString();
+    }
+
+    /**
+     * @see org.apache.harmony.security.asn1.BerInputStream#readSequence(org.apache.harmony.security.asn1.ASN1Sequence)
+     */
+    public void readSequence(ASN1Sequence sequence) throws IOException {
+        //
+        // According to ASN.1 DER spec. sequence MUST not include
+        // any encoding which value is equal to its default value
+        //
+        // Verification of this assertion is not implemented
+        //
+        super.readSequence(sequence);
+    }
+
+    /**
+     * @see org.apache.harmony.security.asn1.BerInputStream#readSetOf(org.apache.harmony.security.asn1.ASN1SetOf)
+     */
+    public void readSetOf(ASN1SetOf setOf) throws IOException {
+        //
+        // According to ASN.1 DER spec. set of MUST appear in
+        // ascending order (short component are padded for comparison)
+        //
+        // Verification of this assertion is not implemented
+        //
+        super.readSetOf(setOf);
+    }
+
+    /**
+     * @see org.apache.harmony.security.asn1.BerInputStream#readString(ASN1StringType)
+     */
+    public void readString(ASN1StringType type) throws IOException {
+
+        if (tag == type.constrId) {
+            throw new ASN1Exception(Messages.getString("security.10A", tagOffset)); //$NON-NLS-1$
+        }
+        super.readString(type);
+    }
+
+    /**
+     * @see org.apache.harmony.security.asn1.BerInputStream#readUTCTime()
+     */
+    public void readUTCTime() throws IOException {
+
+        if (tag == ASN1Constants.TAG_C_UTCTIME) {
+            // It is a string type and it can be encoded as primitive or constructed.
+            throw new ASN1Exception(Messages.getString("security.10B", tagOffset)); //$NON-NLS-1$
+        }
+
+        // check format: DER uses YYMMDDHHMMSS'Z' only
+        if (length != ASN1UTCTime.UTC_HMS) {
+            throw new ASN1Exception(Messages.getString("security.10C", tagOffset)); //$NON-NLS-1$
+        }
+
+        super.readUTCTime();
+    }
+
+    /**
+     * @see org.apache.harmony.security.asn1.BerInputStream#readGeneralizedTime()
+     */
+    public void readGeneralizedTime() throws IOException {
+
+        if (tag == ASN1Constants.TAG_C_GENERALIZEDTIME) {
+            // It is a string type and it can be encoded as primitive or constructed.
+            throw new ASN1Exception(Messages.getString("security.10D", tagOffset)); //$NON-NLS-1$
+        }
+
+        super.readGeneralizedTime();
+
+        // FIXME makes sense only if we support all GeneralizedTime formats 
+        // late check syntax: the last char MUST be Z
+        //if (buffer[offset - 1] != 'Z') {
+        //    throw new ASN1Exception(
+        //            "ASN.1 GeneralizedTime wrongly encoded at ["
+        //                    + contentOffset + ']');
+        //}
+
+        // the fractional-seconds elements, if present MUST
+        // omit all trailing zeros
+        // FIXME implement me
+        //        if () {
+        //            throw new IOException(
+        //                    "DER ASN.1 GeneralizedTime wrongly encoded at ["
+        //                            + contentOffset
+        //                            + "]. Trailing zeros MUST be omitted");
+        //        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/DerOutputStream.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/DerOutputStream.java
new file mode 100644
index 0000000..eb78d2c
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/DerOutputStream.java
@@ -0,0 +1,258 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+
+/**
+ * Encodes ASN.1 types with DER (X.690)
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public final class DerOutputStream extends BerOutputStream {
+
+    public DerOutputStream(ASN1Type asn1, Object object) {
+        super();
+
+        content = object;
+
+        index = -1;
+        asn1.setEncodingContent(this);
+
+        encoded = new byte[asn1.getEncodedLength(this)];
+
+        index = 0;
+        asn1.encodeASN(this);
+    }
+
+    public void encodeChoice(ASN1Choice choice) {
+
+        ASN1Type type = (ASN1Type) val[index][0];
+
+        content = val[index][1];
+
+        index++;
+
+        type.encodeASN(this);
+    }
+
+    public void encodeExplicit(ASN1Explicit explicit) {
+
+        content = val[index][0];
+        length = len[index][0];
+
+        index++;
+
+        explicit.type.encodeASN(this);
+    }
+
+    public void encodeSequence(ASN1Sequence sequence) {
+
+        ASN1Type[] type = sequence.type;
+
+        Object[] values = val[index];
+        int[] compLens = len[index];
+
+        index++;
+        for (int i = 0; i < type.length; i++) {
+
+            if (values[i] == null) {
+                continue;
+            }
+
+            content = values[i];
+            length = compLens[i];
+
+            type[i].encodeASN(this);
+        }
+    }
+
+    public void encodeSequenceOf(ASN1SequenceOf sequenceOf) {
+        encodeValueCollection(sequenceOf);
+    }
+
+    public void encodeSetOf(ASN1SetOf setOf) {
+        encodeValueCollection(setOf);
+    }
+
+    private final void encodeValueCollection(ASN1ValueCollection collection) {
+
+        Object[] values = val[index];
+        int[] compLens = len[index];
+
+        index++;
+        for (int i = 0; i < values.length; i++) {
+
+            content = values[i];
+            length = compLens[i];
+
+            collection.type.encodeASN(this);
+        }
+    }
+
+    /*
+     * DATA
+     */
+
+    private final static int initSize = 32;
+
+    private int index;
+
+    private int[][] len = new int[initSize][];
+
+    private Object[][] val = new Object[initSize][];
+
+    private void push(int[] lengths, Object[] values) {
+
+        index++;
+        if (index == val.length) {
+
+            int[][] newLen = new int[val.length * 2][];
+            System.arraycopy(len, 0, newLen, 0, val.length);
+            len = newLen;
+
+            Object[][] newVal = new Object[val.length * 2][];
+            System.arraycopy(val, 0, newVal, 0, val.length);
+            val = newVal;
+        }
+        len[index] = lengths;
+        val[index] = values;
+    }
+
+    /*
+     * LENGTH 
+     */
+
+    public void getChoiceLength(ASN1Choice choice) {
+
+        int i = choice.getIndex(content);
+        content = choice.getObjectToEncode(content);
+
+        Object[] values = new Object[] { choice.type[i], content };
+
+        push(null, values);
+
+        choice.type[i].setEncodingContent(this);
+
+        // in case if we get content bytes while getting its length
+        // FIXME what about remove it: need redesign
+        values[1] = content;
+    }
+
+    public void getExplicitLength(ASN1Explicit explicit) {
+
+        Object[] values = new Object[1];
+        int[] compLens = new int[1];
+
+        values[0] = content;
+
+        push(compLens, values);
+
+        explicit.type.setEncodingContent(this);
+
+        // in case if we get content bytes while getting its length
+        // FIXME what about remove it: need redesign
+        values[0] = content;
+        compLens[0] = length;
+
+        length = explicit.type.getEncodedLength(this);
+    }
+
+    public void getSequenceLength(ASN1Sequence sequence) {
+
+        ASN1Type[] type = sequence.type;
+
+        Object[] values = new Object[type.length];
+        int[] compLens = new int[type.length];
+
+        sequence.getValues(content, values);
+
+        push(compLens, values);
+
+        int seqLen = 0;
+        for (int i = 0; i < type.length; i++) {
+            // check optional types
+            if (values[i] == null) {
+                if (sequence.OPTIONAL[i]) {
+                    continue;
+                } else {
+                    throw new RuntimeException();//FIXME type & message
+                }
+            }
+
+            if (sequence.DEFAULT[i] != null
+                    && sequence.DEFAULT[i].equals(values[i])) {
+                values[i] = null;
+                continue;
+            }
+
+            content = values[i];
+
+            type[i].setEncodingContent(this);
+
+            compLens[i] = length;
+
+            // in case if we get content bytes while getting its length
+            // FIXME what about remove it: need redesign
+            values[i] = content;
+
+            seqLen += type[i].getEncodedLength(this);
+        }
+        length = seqLen;
+    }
+
+    public void getSequenceOfLength(ASN1SequenceOf sequence) {
+        getValueOfLength(sequence);
+    }
+
+    public void getSetOfLength(ASN1SetOf setOf) {
+        getValueOfLength(setOf);
+    }
+
+    private void getValueOfLength(ASN1ValueCollection collection) {
+
+        //FIXME what about another way?
+        Object[] cv = collection.getValues(content).toArray();
+
+        Object[] values = new Object[cv.length];
+        int[] compLens = new int[values.length];
+
+        push(compLens, values);
+        int seqLen = 0;
+        for (int i = 0; i < values.length; i++) {
+
+            content = cv[i];
+
+            collection.type.setEncodingContent(this);
+
+            compLens[i] = length;
+
+            // in case if we get content bytes while getting its length
+            // FIXME what about remove it: need redesign
+            values[i] = content;
+
+            seqLen += collection.type.getEncodedLength(this);
+        }
+        length = seqLen;
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/InformationObjectSet.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/InformationObjectSet.java
new file mode 100644
index 0000000..2a267e5
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/InformationObjectSet.java
@@ -0,0 +1,108 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.util.Arrays;
+
+import org.apache.harmony.security.x501.AttributeType;
+
+
+/**
+ * Represents Information Object Set. 
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public class InformationObjectSet {
+
+    private final int capacity;
+
+    private final Entry[][] pool;
+
+    public InformationObjectSet() {
+        this(64, 10);
+    }
+
+    public InformationObjectSet(int capacity, int size) {
+        this.capacity = capacity;
+        pool = new Entry[capacity][size];
+    }
+
+    public void put(AttributeType at) {
+        put(at.oid.getOid(), at);
+    }
+
+    public void put(int[] oid, Object object) {
+
+        int index = hashIntArray(oid) % capacity;
+        // look for OID in the pool 
+        Entry[] list = pool[index];
+        int i = 0;
+        for (; list[i] != null; i++) {
+
+            // check wrong static initialization: no duplicate OIDs
+            if (Arrays.equals(oid, list[i].oid)) {
+                throw new Error(); //FIXME message
+            }
+        }
+
+        // check : to avoid NPE
+        if (i == (capacity - 1)) {
+            throw new Error(); //FIXME message
+        }
+        list[i] = new Entry(oid, object);
+    }
+
+    public Object get(int[] oid) {
+        int index = hashIntArray(oid) % capacity;
+
+        // look for OID in the pool 
+        Entry[] list = pool[index];
+        for (int i = 0; list[i] != null; i++) {
+            if (Arrays.equals(oid, list[i].oid)) {
+                return list[i].object;
+            }
+        }
+        return null;
+    }
+
+    // FIXME change me to Arrays.hashCode(int[])
+    private int hashIntArray(int[] array) {
+        int intHash = 0;
+        for (int i = 0; i < array.length && i < 4; i++) {
+            intHash += array[i] << (8 * i); //TODO what about to find better one?
+        }
+        return intHash & 0x7FFFFFFF; // only positive
+    }
+
+    private class Entry {
+        public int[] oid;
+
+        public Object object;
+
+        public Entry(int[] oid, Object object) {
+            this.oid = oid;
+            this.object = object;
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/asn1/ObjectIdentifier.java b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ObjectIdentifier.java
new file mode 100644
index 0000000..0e7269a
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/asn1/ObjectIdentifier.java
@@ -0,0 +1,382 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.asn1;
+
+import java.util.Arrays;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * Instance of this class represents ObjectIdentifier (OID).
+ * 
+ * According to X.690:
+ * OID is represented as a sequence of subidentifier.
+ * Each subidentifier is represented as non negative integer value.
+ * There are at least 2 subidentifiers in the sequence.
+ * 
+ * Valid values for first subidentifier are 0, 1 and 2.
+ * If the first subidentifier has 0 or 1 value the second
+ * subidentifier must be less then 40.
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public final class ObjectIdentifier {
+
+    // OID as array of integers
+    private final int[] oid;
+
+    // OID as string
+    private String soid;
+
+    /**
+     * Creates ObjectIdentifier(OID) from array of integers.
+     * 
+     * @param oid - array of integers
+     * @throws IllegalArgumentException - if oid is invalid or null
+     */
+    public ObjectIdentifier(int[] oid) {
+        validate(oid);
+        this.oid = oid;
+    }
+
+    /**
+     * Creates ObjectIdentifier(OID) from string representation.
+     * 
+     * @param strOid - oid string
+     * @throws IllegalArgumentException - if oid string is invalid or null
+     */
+    public ObjectIdentifier(String strOid) {
+        this.oid = toIntArray(strOid);
+        this.soid = strOid;
+    }
+
+    /**
+     * Returns array of integers.
+     * 
+     * @return array of integers
+     */
+    public int[] getOid() {
+        return oid;
+    }
+
+    /**
+     * Compares object with OID for equality.
+     * 
+     * @return true if object is ObjectIdentifier and it has the same
+     *         representation as array of integers, otherwise false
+     */
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || this.getClass() != o.getClass()) {
+            return false;
+        }
+        return Arrays.equals(oid, ((ObjectIdentifier) o).oid);
+    }
+
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString() {
+        if (soid == null) {
+            soid = toString(oid);
+        }
+        return soid;
+    }
+
+    /**
+     * @see java.lang.Object#hashCode()
+     */
+    public int hashCode() {
+        // FIXME change me to Arrays.hashCode(int[])
+        int intHash = 0;
+        for (int i = 0; i < oid.length && i < 4; i++) {
+            intHash += oid[i] << (8 * i); //TODO what about to find better one?
+        }
+        return intHash & 0x7FFFFFFF; // only positive
+    }
+
+    /**
+     * Validates ObjectIdentifier (OID).
+     * 
+     * @param oid - oid as array of integers
+     * @throws IllegalArgumentException - if oid is invalid or null
+     */
+    public static void validate(int[] oid) {
+
+        if (oid == null) {
+            throw new IllegalArgumentException(Messages.getString("security.98")); //$NON-NLS-1$
+        }
+
+        if (oid.length < 2) {
+            throw new IllegalArgumentException(
+                    Messages.getString("security.99")); //$NON-NLS-1$
+        }
+
+        if (oid[0] > 2) {
+            throw new IllegalArgumentException(
+                    Messages.getString("security.9A")); //$NON-NLS-1$
+        } else if (oid[0] != 2 && oid[1] > 39) {
+            throw new IllegalArgumentException(
+                    Messages.getString("security.9B")); //$NON-NLS-1$
+        }
+
+        for (int i = 0; i < oid.length; i++) {
+            if (oid[i] < 0) {
+                throw new IllegalArgumentException(
+                        Messages.getString("security.9C")); //$NON-NLS-1$
+            }
+        }
+    }
+
+    // FIXME: implement me
+    //    /**
+    //     * Validates ObjectIdentifier (OID).
+    //     * 
+    //     * @param oid - oid as string
+    //     * @throws IllegalArgumentException - if oid string  is invalid or null
+    //     */
+    //    public static void validate(String oid) {
+    //
+    //        if (oid == null) {
+    //            throw new NullPointerException();
+    //        }
+    //
+    //        int length = oid.length();
+    //        if (length < 3 || oid.charAt(1) != '.') {
+    //            throw new IllegalArgumentException("Invalid oid string");
+    //        }
+    //
+    //        int pos = 2;
+    //        int subidentifier = 0;
+    //        switch (oid.charAt(0)) {
+    //        case '0':
+    //        case '1':
+    //            for (char c = oid.charAt(pos);;) {
+    //                if (c < '0' || c > '9') {
+    //                    throw new IllegalArgumentException("Invalid oid string");
+    //                } else {
+    //                    subidentifier = subidentifier * 10 + c - '0';
+    //                }
+    //
+    //                pos++;
+    //                if (pos == length) {
+    //                    break;
+    //                }
+    //
+    //                c = oid.charAt(pos);
+    //                if (c == '.') {
+    //                    pos++;
+    //                    if (pos == length) {
+    //                        throw new IllegalArgumentException("Invalid oid string");
+    //                    }
+    //                    break;
+    //                }
+    //            }
+    //
+    //            if (subidentifier > 39) {
+    //                throw new IllegalArgumentException(
+    //                        "If the first subidentifier has 0 or 1 value the second "
+    //                                + "subidentifier value MUST be less then 40.");
+    //            }
+    //            break;
+    //        case '2':
+    //            break;
+    //        default:
+    //            throw new IllegalArgumentException(
+    //                    "Valid values for first subidentifier are 0, 1 and 2");
+    //        }
+    //
+    //        if (pos == length) {
+    //            return;
+    //        }
+    //
+    //        for (char c = oid.charAt(pos);;) {
+    //            if (c < '0' || c > '9') {
+    //                throw new IllegalArgumentException("Invalid oid string");
+    //            }
+    //
+    //            pos++;
+    //            if (pos == length) {
+    //                return;
+    //            }
+    //
+    //            c = oid.charAt(pos);
+    //            if (c == '.') {
+    //                pos++;
+    //                if (pos == length) {
+    //                    throw new IllegalArgumentException("Invalid oid string");
+    //                }
+    //            }
+    //        }
+    //    }
+
+    /**
+     * Returns string representation of OID.
+     * 
+     * Note: it is supposed that passed array of integers
+     * contains valid OID value, so no checks are performed. 
+     *
+     * @param oid - oid as array of integers
+     * @return oid string representation
+     */
+    public static String toString(int[] oid) {
+        StringBuffer sb = new StringBuffer(3 * oid.length);
+
+        for (int i = 0; i < oid.length - 1; ++i) {
+            sb.append(oid[i]);
+            sb.append('.');
+        }
+        sb.append(oid[oid.length - 1]);
+        return sb.toString();
+    }
+
+    // BEGIN android-changed
+    /**
+     * Gets ObjectIdentifier (OID) from string representation.
+     * 
+     * String representation is defined by the following syntax:
+     *     OID = subidentifier 1*("." subidentifier)
+     *     subidentifier = 1*(digit)
+     * 
+     * @param oidString -  string representation of OID
+     * @return - oid as array of integers
+     * @throws IllegalArgumentException - if oid string is invalid or null
+     */
+    public static int[] toIntArray(String str) {
+        return toIntArray(str, true);
+    }
+    
+    /**
+     * Returns whether the given string is a valid ObjectIdentifier
+     * (OID) representation.
+     * 
+     * String representation is defined as for {@link #toIntArray}.
+     * 
+     * @param oidString -  string representation of OID
+     * @return true if oidString has valid syntax or false if not
+     */
+    public static boolean isOID(String str) {
+        return toIntArray(str, false) != null;
+    }
+
+    /**
+     * Gets ObjectIdentifier (OID) from string representation.
+     * 
+     * String representation is defined by the following syntax:
+     *     OID = subidentifier 1*("." subidentifier)
+     *     subidentifier = 1*(digit)
+     * 
+     * @param oidString -  string representation of OID
+     * @return - oid as array of integers or null if the oid string is
+     * invalid or null and shouldThrow is false
+     * @throws IllegalArgumentException - if oid string is invalid or null and
+     * shouldThrow is true
+     */
+    private static int[] toIntArray(String str, boolean shouldThrow) {
+        if (str == null) {
+            if (! shouldThrow) {
+                return null;
+            }
+            throw new IllegalArgumentException(
+                    Messages.getString("security.9D")); //$NON-NLS-1$
+        }
+
+        int length = str.length();
+        if (length == 0) {
+            if (! shouldThrow) {
+                return null;
+            }
+            throw new IllegalArgumentException(Messages.getString("security.9E")); //$NON-NLS-1$
+        }
+
+        int count = 1; // number of subidentifiers
+        boolean wasDot = true; // indicates whether char before was dot or not.
+        char c; // current char
+        for (int i = 0; i < length; i++) {
+            c = str.charAt(i);
+            if (c == '.') {
+                if (wasDot) {
+                    if (! shouldThrow) {
+                        return null;
+                    }
+                    throw new IllegalArgumentException(Messages.getString("security.9E")); //$NON-NLS-1$
+                }
+                wasDot = true;
+                count++;
+            } else if (c >= '0' && c <= '9') {
+                wasDot = false;
+            } else {
+                if (! shouldThrow) {
+                    return null;
+                }
+                throw new IllegalArgumentException(Messages.getString("security.9E")); //$NON-NLS-1$
+            }
+        }
+
+        if (wasDot) {
+            // the last char is dot
+            if (! shouldThrow) {
+                return null;
+            }
+            throw new IllegalArgumentException(Messages.getString("security.9E")); //$NON-NLS-1$
+        }
+
+        if (count < 2) {
+            if (! shouldThrow) {
+                return null;
+            }
+            throw new IllegalArgumentException(
+                    Messages.getString("security.99")); //$NON-NLS-1$
+        }
+
+        int[] oid = new int[count];
+        for (int i = 0, j = 0; i < length; i++) {
+            c = str.charAt(i);
+            if (c == '.') {
+                j++;
+            } else {
+                oid[j] = oid[j] * 10 + c - 48; // '0' = 48
+            }
+        }
+
+        if (oid[0] > 2) {
+            if (! shouldThrow) {
+                return null;
+            }
+            throw new IllegalArgumentException(
+                    Messages.getString("security.9A")); //$NON-NLS-1$
+        } else if (oid[0] != 2 && oid[1] > 39) {
+            if (! shouldThrow) {
+                return null;
+            }
+            throw new IllegalArgumentException(
+                    Messages.getString("security.9B")); //$NON-NLS-1$
+        }
+
+        return oid;
+    }
+    // END android-changed
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/fortress/DefaultPolicy.java b/libcore/security/src/main/java/org/apache/harmony/security/fortress/DefaultPolicy.java
new file mode 100644
index 0000000..8c26f62
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/fortress/DefaultPolicy.java
@@ -0,0 +1,311 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.fortress;
+
+import java.io.File;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Policy;
+import java.security.ProtectionDomain;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import org.apache.harmony.security.PolicyEntry;
+
+
+/**
+ * Default Policy implementation based on policy configuration files. This
+ * implementation recognizes text files, consisting of clauses with the
+ * following syntax:
+ * 
+ * <pre>
+ * keystore &quot;some_keystore_url&quot; [, &quot;keystore_type&quot;];
+ * </pre>
+ <pre>
+ * grant [SignedBy &quot;signer_names&quot;] [, CodeBase &quot;URL&quot;]
+ *  [, Principal [principal_class_name] &quot;principal_name&quot;]
+ *  [, Principal [principal_class_name] &quot;principal_name&quot;] ... {
+ *  permission permission_class_name [ &quot;target_name&quot; ] [, &quot;action&quot;] 
+ *  [, SignedBy &quot;signer_names&quot;];
+ *  permission ...
+ *  };
+ *  
+ * </pre>
+ * 
+ * The <i>keystore </i> clause specifies reference to a keystore, which is a
+ * database of private keys and their associated digital certificates. The
+ * keystore is used to look up the certificates of signers specified in the
+ * <i>grant </i> entries of the file. The policy file can contain any number of
+ * <i>keystore </i> entries which can appear at any ordinal position. However,
+ * only the first successfully loaded keystore is used, others are ignored. The
+ * keystore must be specified if some grant clause refers to a certificate's
+ * alias. <br>
+ * The <i>grant </i> clause associates a CodeSource (consisting of an URL and a
+ * set of certificates) of some executable code with a set of Permissions which
+ * should be granted to the code. So, the CodeSource is defined by values of
+ * <i>CodeBase </i> and <i>SignedBy </i> fields. The <i>CodeBase </i> value must
+ * be in URL format, while <i>SignedBy </i> value is a (comma-separated list of)
+ * alias(es) to keystore certificates. These fields can be omitted to denote any
+ * codebase and any signers (including case of unsigned code), respectively.
+ * <br>
+ * Also, the code may be required to be executed on behalf of some Principals
+ * (in other words, code's ProtectionDomain must have the array of Principals
+ * associated) in order to possess the Permissions. This fact is indicated by
+ * specifying one or more <i>Principal </i> fields in the <i>grant </i> clause.
+ * Each Principal is specified as class/name pair; name and class can be either
+ * concrete value or wildcard <i>* </i>. As a special case, the class value may
+ * be omitted and then the name is treated as an alias to X.509 Certificate, and
+ * the Principal is assumed to be javax.security.auth.x500.X500Principal with a
+ * name of subject's distinguished name from the certificate. <br>
+ * The order between the <i>CodeBase </i>, <i>SignedBy </i>, and <i>Principal
+ * </i> fields does not matter. The policy file can contain any number of grant
+ * clauses. <br>
+ * Each <i>grant </i> clause must contain one or more <i>permission </i> entry.
+ * The permission entry consist of a fully qualified class name along with
+ * optional <i>name </i>, <i>actions </i> and <i>signedby </i> values. Name and
+ * actions are arguments to the corresponding constructor of the permission
+ * class. SignedBy value represents the keystore alias(es) to certificate(s)
+ * used to sign the permission class. That is, this permission entry is
+ * effective (i.e., access control permission will be granted based on this
+ * entry) only if the bytecode implementation of permission class is verified to
+ * be correctly signed by the said alias(es). <br>
+ * <br>
+ * The policy content may be parameterized via property expansion. Namely,
+ * expressions like <i>${key} </i> are replaced by values of corresponding
+ * system properties. Also, the special <i>slash </i> key (i.e. ${/}) is
+ * supported, it is a shortcut to &quot;file.separator&quot; key. Property
+ * expansion is performed anywhere a double quoted string is allowed in the
+ * policy file. However, this feature is controlled by security properties and
+ * should be turned on by setting &quot;policy.expandProperties&quot; property
+ * to <i>true </i>. <br>
+ * If property expansion fails (due to a missing key), a corresponding entry is
+ * ignored. For fields of <i>keystore </i> and <i>grant </i> clauses, the whole
+ * clause is ignored, and for <i>permission </i> entry, only that entry is
+ * ignored. <br>
+ * <br>
+ * The policy also supports generalized expansion in permissions names, of
+ * expressions like <i>${{protocol:data}} </i>. Currently the following
+ * protocols supported:
+ * <dl>
+ * <dt>self
+ * <dd>Denotes substitution to a principal information of the parental Grant
+ * entry. Replaced by a space-separated list of resolved Principals (including
+ * wildcarded), each formatted as <i>class &quot;name&quot; </i>. If parental
+ * Grant entry has no Principals, the permission is ignored.
+ * <dt>alias: <i>name </i>
+ * <dd>Denotes substitution of a KeyStore alias. Namely, if a KeyStore has an
+ * X.509 certificate associated with the specified name, then replaced by
+ * <i>javax.security.auth.x500.X500Principal &quot; <i>DN </i>&quot; </i>
+ * string, where <i>DN </i> is a certificate's subject distinguished name.
+ * </dl>
+ * <br>
+ * <br>
+ * This implementation is thread-safe. The policy caches sets of calculated
+ * permissions for the requested objects (ProtectionDomains and CodeSources) via
+ * WeakHashMap; the cache is cleaned either explicitly during refresh()
+ * invocation, or naturally by garbage-collecting the corresponding objects.
+ * 
+ * @see org.apache.harmony.security.fortress.PolicyUtils#getPolicyURLs(Properties, String,
+ *      String)
+ */
+
+public class DefaultPolicy extends Policy {
+
+    /**
+     * System property for dynamically added policy location.
+     */
+    public static final String JAVA_SECURITY_POLICY = "java.security.policy"; //$NON-NLS-1$
+
+    /**
+     * Prefix for numbered Policy locations specified in security.properties.
+     */
+    public static final String POLICY_URL_PREFIX = "policy.url."; //$NON-NLS-1$
+
+    // A set of PolicyEntries constituting this Policy.
+    private final Set<PolicyEntry> grants = new HashSet<PolicyEntry>();
+
+    // Calculated Permissions cache, organized as
+    // Map{Object->Collection&lt;Permission&gt;}.
+    // The Object is a ProtectionDomain, a CodeSource or
+    // any other permissions-granted entity.
+    private final Map<Object, Collection<Permission>> cache = new WeakHashMap<Object, Collection<Permission>>();
+
+    // A specific parser for a particular policy file format.
+    private final DefaultPolicyParser parser;
+
+    // A flag indicating brand new instance which needs to be loaded
+    // on the first appeal to it's data.
+    private boolean initiailized;
+
+    /**
+     * Default constructor, equivalent to
+     * <code>DefaultPolicy(new DefaultPolicyParser())</code>.
+     */
+    public DefaultPolicy() {
+        this(new DefaultPolicyParser());
+    }
+
+    /**
+     * Extension constructor for plugging-in a custom parser. Defers policy data
+     * initialization before the first <code>getPermissions()</code> call
+     * (though policy may be refreshed explicitly, as well).
+     */
+    public DefaultPolicy(DefaultPolicyParser dpr) {
+        parser = dpr;
+        initiailized = false;
+        refresh();
+    }
+
+    /**
+     * Returns collection of permissions allowed for the domain 
+     * according to the policy. The evaluated characteristics of the 
+     * domain are it's codesource and principals; they are assumed
+     * to be <code>null</code> if the domain is <code>null</code>.
+     */
+    public PermissionCollection getPermissions(ProtectionDomain pd) {
+        if (!initiailized) {
+            synchronized (this) {
+                if (!initiailized) {
+                    refresh();
+                }
+            }
+        }
+        Collection<Permission> pc = cache.get(pd);
+        if (pc == null) {
+            //have to synchronize to exclude cache pollution after refresh
+            synchronized (cache) {
+
+                // double check in case value has been put to cache
+                // while we've been awaiting monitor
+                pc = cache.get(pd);
+                if (pc == null) {
+                    pc = new HashSet<Permission>();
+                    Iterator<PolicyEntry> it = grants.iterator();
+                    while (it.hasNext()) {
+                        PolicyEntry ge = (PolicyEntry)it.next();
+                        if (ge.impliesPrincipals(pd == null ? null : pd.getPrincipals())
+                            && ge.impliesCodeSource(pd == null ? null : pd.getCodeSource())) {
+                            pc.addAll(ge.getPermissions());
+                        }
+                    }
+                    cache.put(pd, pc);
+                }
+            }
+        }
+        return PolicyUtils.toPermissionCollection(pc);
+
+    }
+
+    /**
+     * Returns collection of permissions allowed for the codesource 
+     * according to the policy. 
+     * The evaluation assumes that current principals are undefined.
+     */
+    public PermissionCollection getPermissions(CodeSource cs) {
+        if (!initiailized) {
+            synchronized (this) {
+                if (!initiailized) {
+                    refresh();
+                }
+            }
+        }
+        Collection<Permission> pc = cache.get(cs);
+        if (pc == null) {
+            //have to synchronize to exclude cache pollution after refresh
+            synchronized (cache) {
+
+                // double check in case value has been put to cache
+                // while we've been awaiting monitor
+                pc = cache.get(cs);
+                if (pc == null) {
+                    pc = new HashSet<Permission>();
+                    Iterator<PolicyEntry> it = grants.iterator();
+                    while (it.hasNext()) {
+                        PolicyEntry ge = (PolicyEntry)it.next();
+                        if (ge.impliesPrincipals(null)
+                            && ge.impliesCodeSource(cs)) {
+                            pc.addAll(ge.getPermissions());
+                        }
+                    }
+                    cache.put(cs, pc);
+                }
+            }
+        }
+        return PolicyUtils.toPermissionCollection(pc);
+    }
+
+    /**
+     * Gets fresh list of locations and tries to load all of them in sequence;
+     * failed loads are ignored. After processing all locations, old policy
+     * settings are discarded and new ones come into force. <br>
+     * This method is declared synchronized to avoid concurrent reloading.
+     * 
+     * @see PolicyUtils#getPolicyURLs(Properties, String, String)
+     */
+    public synchronized void refresh() {
+        Set<PolicyEntry> fresh = new HashSet<PolicyEntry>();
+        Properties system = new Properties(AccessController
+                .doPrivileged(new PolicyUtils.SystemKit()));
+        system.setProperty("/", File.separator); //$NON-NLS-1$
+        URL[] policyLocations = PolicyUtils.getPolicyURLs(system,
+                                                          JAVA_SECURITY_POLICY,
+                                                          POLICY_URL_PREFIX);
+        for (int i = 0; i < policyLocations.length; i++) {
+            try {
+                //TODO debug log
+                //System.err.println("Parsing policy file: " + policyLocations[i]);
+                fresh.addAll(parser.parse(policyLocations[i], system));
+            } catch (Exception e) {
+                // TODO log warning
+                //System.err.println("Ignoring policy file: " 
+                //                 + policyLocations[i] + ". Reason:\n"+ e);
+            }
+        }
+        // XXX: what if new policy is empty - provide some default??
+
+        // we could safely replace references instead of
+        // synchronizing access:
+        // <pre>
+        // grants = fresh;
+        // cache = new WeakHashMap();
+        // </pre>
+        // but there is possibility that concurrent thread will put
+        // old data to cache right after we finish refresh(),
+        // thus synchronization is added in getPermissions() methods...
+        synchronized (cache) {
+            grants.clear();
+            grants.addAll(fresh);
+
+            cache.clear();
+        }
+        initiailized = true;
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/fortress/DefaultPolicyParser.java b/libcore/security/src/main/java/org/apache/harmony/security/fortress/DefaultPolicyParser.java
new file mode 100644
index 0000000..41d6056
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/fortress/DefaultPolicyParser.java
@@ -0,0 +1,497 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.fortress;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.File;
+import java.io.Reader;
+import java.net.URL;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.security.AccessController;
+import java.security.CodeSource;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.Permission;
+import java.security.Principal;
+import java.security.UnresolvedPermission;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import org.apache.harmony.security.DefaultPolicyScanner;
+import org.apache.harmony.security.PolicyEntry;
+import org.apache.harmony.security.UnresolvedPrincipal;
+import org.apache.harmony.security.DefaultPolicyScanner.GrantEntry;
+import org.apache.harmony.security.DefaultPolicyScanner.KeystoreEntry;
+import org.apache.harmony.security.DefaultPolicyScanner.PermissionEntry;
+import org.apache.harmony.security.DefaultPolicyScanner.PrincipalEntry;
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * This is a basic loader of policy files. It delegates lexical analysis to 
+ * a pluggable scanner and converts received tokens to a set of 
+ * {@link org.apache.harmony.security.PolicyEntry PolicyEntries}. 
+ * For details of policy format, see the 
+ * {@link org.apache.harmony.security.fortress.DefaultPolicy default policy description}.
+ * <br>
+ * For ordinary uses, this class has just one public method <code>parse()</code>, 
+ * which performs the main task.
+ * Extensions of this parser may redefine specific operations separately, 
+ * by overriding corresponding protected methods. 
+ * <br>
+ * This implementation is effectively thread-safe, as it has no field references 
+ * to data being processed (that is, passes all the data as method parameters).
+ * 
+ * @see org.apache.harmony.security.fortress.DefaultPolicy
+ * @see org.apache.harmony.security.DefaultPolicyScanner
+ * @see org.apache.harmony.security.PolicyEntry
+ */
+public class DefaultPolicyParser {
+
+    // Pluggable scanner for a specific file format
+    private final DefaultPolicyScanner scanner;
+
+    /** 
+     * Default constructor, 
+     * {@link org.apache.harmony.security.DefaultPolicyScanner DefaultPolicyScanner} 
+     * is used. 
+     */
+    public DefaultPolicyParser() {
+        scanner = new DefaultPolicyScanner();
+    }
+
+    /** 
+     * Extension constructor for plugging-in custom scanner.
+     */
+    public DefaultPolicyParser(DefaultPolicyScanner s) {
+        this.scanner = s;
+    }
+
+    /**
+     * This is the main business method. It manages loading process as follows:
+     * the associated scanner is used to parse the stream to a set of 
+     * {@link org.apache.harmony.security.DefaultPolicyScanner.GrantEntry composite tokens},
+     * then this set is iterated and each token is translated to a PolicyEntry.
+     * Semantically invalid tokens are ignored, the same as void PolicyEntries.
+     * <br>
+     * A policy file may refer to some KeyStore(s), and in this case the first
+     * valid reference is initialized and used in processing tokens.   
+     * 
+     * @param location an URL of a policy file to be loaded
+     * @param system system properties, used for property expansion
+     * @return a collection of PolicyEntry objects, may be empty
+     * @throws Exception IO error while reading location or file syntax error 
+     */
+    public Collection<PolicyEntry>parse(URL location, Properties system)
+            throws Exception {
+
+        boolean resolve = PolicyUtils.canExpandProperties();
+        // BEGIN android-modified
+        Reader r =
+            new BufferedReader(
+                    new InputStreamReader(
+                            AccessController.doPrivileged(
+                                    new PolicyUtils.URLLoader(location))),
+                    8192);
+        // END android-modified
+
+        Collection<GrantEntry> grantEntries = new HashSet<GrantEntry>();
+        List<KeystoreEntry> keystores = new ArrayList<KeystoreEntry>();
+
+        try {
+            scanner.scanStream(r, grantEntries, keystores);
+        }
+        finally {
+            r.close();
+        }
+
+        //XXX KeyStore could be loaded lazily...
+        KeyStore ks = initKeyStore(keystores, location, system, resolve);
+
+        Collection<PolicyEntry> result = new HashSet<PolicyEntry>();
+        for (Iterator<GrantEntry> iter = grantEntries.iterator(); iter.hasNext();) {
+            DefaultPolicyScanner.GrantEntry ge = iter
+                    .next();
+            try {
+                PolicyEntry pe = resolveGrant(ge, ks, system, resolve);
+                if (!pe.isVoid()) {
+                    result.add(pe);
+                }
+            }
+            catch (Exception e) {
+                // TODO: log warning
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Translates GrantEntry token to PolicyEntry object. It goes step by step, 
+     * trying to resolve each component of the GrantEntry:
+     * <ul>
+     * <li> If <code>codebase</code> is specified, expand it and construct an URL.
+     * <li> If <code>signers</code> is specified, expand it and obtain 
+     * corresponding Certificates.
+     * <li> If <code>principals</code> collection is specified, iterate over it. 
+     * For each PrincipalEntry, expand name and if no class specified, 
+     * resolve actual X500Principal from a KeyStore certificate; otherwise keep it 
+     * as UnresolvedPrincipal. 
+     * <li> Iterate over <code>permissions</code> collection. For each PermissionEntry,
+     * try to resolve (see method 
+     * {@link #resolvePermission(DefaultPolicyScanner.PermissionEntry, DefaultPolicyScanner.GrantEntry, KeyStore, Properties, boolean) resolvePermission()}) 
+     * a corresponding permission. If resolution failed, ignore the PermissionEntry. 
+     * </ul>
+     * In fact, property expansion in the steps above is conditional and is ruled by
+     * the parameter <i>resolve</i>.  
+     * <br>
+     * Finally a new PolicyEntry is created, which associates the trinity 
+     * of resolved URL, Certificates and Principals to a set of granted Permissions.
+     * 
+     * @param ge GrantEntry token to be resolved
+     * @param ks KeyStore for resolving Certificates, may be <code>null</code> 
+     * @param system system properties, used for property expansion 
+     * @param resolve flag enabling/disabling property expansion
+     * @return resolved PolicyEntry
+     * @throws Exception if unable to resolve codebase, signers or principals 
+     * of the GrantEntry
+     * @see DefaultPolicyScanner.PrincipalEntry
+     * @see DefaultPolicyScanner.PermissionEntry
+     * @see org.apache.harmony.security.fortress.PolicyUtils
+     */
+    protected PolicyEntry resolveGrant(DefaultPolicyScanner.GrantEntry ge,
+            KeyStore ks, Properties system, boolean resolve) throws Exception {
+
+        URL codebase = null;
+        Certificate[] signers = null;
+        Set<Principal>principals = new HashSet<Principal>();
+        Set<Permission>permissions = new HashSet<Permission>();
+        if (ge.codebase != null) {
+            codebase = new URL(resolve ? PolicyUtils.expandURL(ge.codebase,
+                    system) : ge.codebase);
+            //Fix HARMONY-1963
+            if ("file".equals(codebase.getProtocol())) { //$NON-NLS-1$
+                File codeFile = new File(codebase.getFile());
+                if (codeFile.isAbsolute()) {
+                    codebase = new URL("file://" +  //$NON-NLS-1$
+                            codeFile.getAbsolutePath());                    
+                }
+            }
+        }
+        if (ge.signers != null) {
+            if (resolve) {
+                ge.signers = PolicyUtils.expand(ge.signers, system);
+            }
+            signers = resolveSigners(ks, ge.signers);
+        }
+        if (ge.principals != null) {
+            for (Iterator<PrincipalEntry> iter = ge.principals.iterator(); iter.hasNext();) {
+                DefaultPolicyScanner.PrincipalEntry pe = iter
+                        .next();
+                if (resolve) {
+                    pe.name = PolicyUtils.expand(pe.name, system);
+                }
+                if (pe.klass == null) {
+                    principals.add(getPrincipalByAlias(ks, pe.name));
+                } else {
+                    principals.add(new UnresolvedPrincipal(pe.klass, pe.name));
+                }
+            }
+        }
+        if (ge.permissions != null) {
+            for (Iterator<PermissionEntry> iter = ge.permissions.iterator(); iter.hasNext();) {
+                DefaultPolicyScanner.PermissionEntry pe = iter
+                        .next();
+                try {
+                    permissions.add(resolvePermission(pe, ge, ks, system,
+                            resolve));
+                }
+                catch (Exception e) {
+                    // TODO: log warning
+                }
+            }
+        }
+        return new PolicyEntry(new CodeSource(codebase, signers), principals,
+                permissions);
+    }
+
+    /**
+     * Translates PermissionEntry token to Permission object.
+     * First, it performs general expansion for non-null <code>name</code> and
+     * properties expansion for non-null <code>name</code>, <code>action</code> 
+     * and <code>signers</code>.
+     * Then, it obtains signing Certificates(if any), tries to find a class specified by 
+     * <code>klass</code> name and instantiate a corresponding permission object.
+     * If class is not found or it is signed improperly, returns UnresolvedPermission.
+     *
+     * @param pe PermissionEntry token to be resolved
+     * @param ge parental GrantEntry of the PermissionEntry 
+     * @param ks KeyStore for resolving Certificates, may be <code>null</code>
+     * @param system system properties, used for property expansion
+     * @param resolve flag enabling/disabling property expansion
+     * @return resolved Permission object, either of concrete class or UnresolvedPermission
+     * @throws Exception if failed to expand properties, 
+     * or to get a Certificate, 
+     * or to create an instance of a successfully found class 
+     */
+    protected Permission resolvePermission(
+            DefaultPolicyScanner.PermissionEntry pe,
+            DefaultPolicyScanner.GrantEntry ge, KeyStore ks, Properties system,
+            boolean resolve) throws Exception {
+        if (pe.name != null) {
+            pe.name = PolicyUtils.expandGeneral(pe.name,
+                    new PermissionExpander().configure(ge, ks));
+        }
+        if (resolve) {
+            if (pe.name != null) {
+                pe.name = PolicyUtils.expand(pe.name, system);
+            }
+            if (pe.actions != null) {
+                pe.actions = PolicyUtils.expand(pe.actions, system);
+            }
+            if (pe.signers != null) {
+                pe.signers = PolicyUtils.expand(pe.signers, system);
+            }
+        }
+        Certificate[] signers = (pe.signers == null) ? null : resolveSigners(
+                ks, pe.signers);
+        try {
+            Class<?> klass = Class.forName(pe.klass);
+            if (PolicyUtils.matchSubset(signers, klass.getSigners())) {
+                return PolicyUtils.instantiatePermission(klass, pe.name,
+                        pe.actions);
+            }
+        }
+        catch (ClassNotFoundException cnfe) {}
+        //maybe properly signed class will be loaded later
+        return new UnresolvedPermission(pe.klass, pe.name, pe.actions, signers);
+    }
+
+    /** 
+     * Specific handler for expanding <i>self</i> and <i>alias</i> protocols. 
+     */
+    class PermissionExpander implements PolicyUtils.GeneralExpansionHandler {
+
+        // Store KeyStore
+        private KeyStore ks;
+
+        // Store GrantEntry
+        private DefaultPolicyScanner.GrantEntry ge;
+
+        /** 
+         * Combined setter of all required fields. 
+         */
+        public PermissionExpander configure(DefaultPolicyScanner.GrantEntry ge,
+                KeyStore ks) {
+            this.ge = ge;
+            this.ks = ks;
+            return this;
+        }
+
+        /**
+         * Resolves the following protocols:
+         * <dl>
+         * <dt>self
+         * <dd>Denotes substitution to a principal information of the parental 
+         * GrantEntry. Returns a space-separated list of resolved Principals 
+         * (including wildcarded), formatting each as <b>class &quot;name&quot;</b>.
+         * If parental GrantEntry has no Principals, throws ExpansionFailedException.
+         * <dt>alias:<i>name</i>
+         * <dd>Denotes substitution of a KeyStore alias. Namely, if a KeyStore has 
+         * an X.509 certificate associated with the specified name, then returns 
+         * <b>javax.security.auth.x500.X500Principal &quot;<i>DN</i>&quot;</b> string, 
+         * where <i>DN</i> is a certificate's subject distinguished name.  
+         * </dl>
+         * @throws ExpansionFailedException - if protocol is other than 
+         * <i>self</i> or <i>alias</i>, or if data resolution failed 
+         */
+        public String resolve(String protocol, String data)
+                throws PolicyUtils.ExpansionFailedException {
+
+            if ("self".equals(protocol)) { //$NON-NLS-1$
+                //need expanding to list of principals in grant clause 
+                if (ge.principals != null && ge.principals.size() != 0) {
+                    StringBuffer sb = new StringBuffer();
+                    for (Iterator<PrincipalEntry> iter = ge.principals.iterator(); iter
+                            .hasNext();) {
+                        DefaultPolicyScanner.PrincipalEntry pr = iter
+                                .next();
+                        if (pr.klass == null) {
+                            // aliased X500Principal
+                            try {
+                                sb.append(pc2str(getPrincipalByAlias(ks,
+                                        pr.name)));
+                            }
+                            catch (Exception e) {
+                                throw new PolicyUtils.ExpansionFailedException(
+                                        Messages.getString("security.143", pr.name), e); //$NON-NLS-1$
+                            }
+                        } else {
+                            sb.append(pr.klass).append(" \"").append(pr.name) //$NON-NLS-1$
+                                    .append("\" "); //$NON-NLS-1$
+                        }
+                    }
+                    return sb.toString();
+                } else {
+                    throw new PolicyUtils.ExpansionFailedException(
+                            Messages.getString("security.144")); //$NON-NLS-1$
+                }
+            }
+            if ("alias".equals(protocol)) { //$NON-NLS-1$
+                try {
+                    return pc2str(getPrincipalByAlias(ks, data));
+                }
+                catch (Exception e) {
+                    throw new PolicyUtils.ExpansionFailedException(
+                            Messages.getString("security.143", data), e); //$NON-NLS-1$
+                }
+            }
+            throw new PolicyUtils.ExpansionFailedException(
+                    Messages.getString("security.145", protocol)); //$NON-NLS-1$
+        }
+
+        // Formats a string describing the passed Principal. 
+        private String pc2str(Principal pc) {
+            String klass = pc.getClass().getName();
+            String name = pc.getName();
+            StringBuffer sb = new StringBuffer(klass.length() + name.length()
+                    + 5);
+            return sb.append(klass).append(" \"").append(name).append("\"") //$NON-NLS-1$ //$NON-NLS-2$
+                    .toString();
+        }
+    }
+
+    /**
+     * Takes a comma-separated list of aliases and obtains corresponding 
+     * certificates.
+     * @param ks KeyStore for resolving Certificates, may be <code>null</code> 
+     * @param signers comma-separated list of certificate aliases, 
+     * must be not <code>null</code>
+     * @return an array of signing Certificates
+     * @throws Exception if KeyStore is <code>null</code> 
+     * or if it failed to provide a certificate  
+     */
+    protected Certificate[] resolveSigners(KeyStore ks, String signers)
+            throws Exception {
+        if (ks == null) {
+            throw new KeyStoreException(Messages.getString("security.146", //$NON-NLS-1$
+                    signers));
+        }
+
+        Collection<Certificate> certs = new HashSet<Certificate>();
+        StringTokenizer snt = new StringTokenizer(signers, ","); //$NON-NLS-1$
+        while (snt.hasMoreTokens()) {
+            //XXX cache found certs ??
+            certs.add(ks.getCertificate(snt.nextToken().trim()));
+        }
+        return certs.toArray(new Certificate[certs.size()]);
+    }
+
+    /**
+     * Returns a subject's X500Principal of an X509Certificate, 
+     * which is associated with the specified keystore alias. 
+     * @param ks KeyStore for resolving Certificate, may be <code>null</code>
+     * @param alias alias to a certificate
+     * @return X500Principal with a subject distinguished name
+     * @throws KeyStoreException if KeyStore is <code>null</code> 
+     * or if it failed to provide a certificate
+     * @throws CertificateException if found certificate is not 
+     * an X509Certificate 
+     */
+    protected Principal getPrincipalByAlias(KeyStore ks, String alias)
+            throws KeyStoreException, CertificateException {
+
+        if (ks == null) {
+            throw new KeyStoreException(
+                    Messages.getString("security.147", alias)); //$NON-NLS-1$
+        }
+        //XXX cache found certs ??
+        Certificate x509 = ks.getCertificate(alias);
+        if (x509 instanceof X509Certificate) {
+            return ((X509Certificate) x509).getSubjectX500Principal();
+        } else {
+            throw new CertificateException(Messages.getString("security.148", //$NON-NLS-1$
+                    alias, x509));
+        }
+    }
+
+    /**
+     * Returns the first successfully loaded KeyStore, from the specified list of
+     * possible locations. This method iterates over the list of KeystoreEntries;
+     * for each entry expands <code>url</code> and <code>type</code>,
+     * tries to construct instances of specified URL and KeyStore and to load 
+     * the keystore. If it is loaded, returns the keystore, otherwise proceeds to 
+     * the next KeystoreEntry. 
+     * <br>
+     * <b>Note:</b> an url may be relative to the policy file location or absolute.
+     * @param keystores list of available KeystoreEntries
+     * @param base the policy file location
+     * @param system system properties, used for property expansion
+     * @param resolve flag enabling/disabling property expansion
+     * @return the first successfully loaded KeyStore or <code>null</code>
+     */
+    protected KeyStore initKeyStore(List<KeystoreEntry>keystores,
+            URL base, Properties system, boolean resolve) {
+
+        for (int i = 0; i < keystores.size(); i++) {
+            try {
+                DefaultPolicyScanner.KeystoreEntry ke = keystores
+                        .get(i);
+                if (resolve) {
+                    ke.url = PolicyUtils.expandURL(ke.url, system);
+                    if (ke.type != null) {
+                        ke.type = PolicyUtils.expand(ke.type, system);
+                    }
+                }
+                if (ke.type == null || ke.type.length() == 0) {
+                    ke.type = KeyStore.getDefaultType();
+                }
+                KeyStore ks = KeyStore.getInstance(ke.type);
+                URL location = new URL(base, ke.url);
+                InputStream is = AccessController
+                        .doPrivileged(new PolicyUtils.URLLoader(location));
+                try {
+                    ks.load(is, null);
+                }
+                finally {
+                    is.close();
+                }
+                return ks;
+            }
+            catch (Exception e) {
+                // TODO: log warning
+            }
+        }
+        return null;
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/fortress/Engine.java b/libcore/security/src/main/java/org/apache/harmony/security/fortress/Engine.java
new file mode 100644
index 0000000..3b6f5d5
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/fortress/Engine.java
@@ -0,0 +1,142 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris V. Kuznetsov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.fortress;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * 
+ * This class implements common functionality for all engine classes
+ * 
+ */
+public class Engine {
+
+    // Service name
+    private String serviceName;
+
+    // for getInstance(String algorithm, Object param) optimization:
+    // previous result
+    private Provider.Service returnedService;
+
+    // previous parameter
+    private String lastAlgorithm;
+
+    private int refreshNumber;
+
+    /**
+     * Provider
+     */
+    public Provider provider;
+
+    /**
+     * SPI instance
+     */
+    public Object spi;
+
+    /**
+     * Access to package visible api in java.security
+     */
+    public static SecurityAccess door;
+
+    /**
+     * Creates a Engine object
+     * 
+     * @param service
+     */
+    public Engine(String service) {
+        this.serviceName = service;
+    }
+
+    /**
+     * 
+     * Finds the appropriate service implementation and creates instance of the
+     * class that implements corresponding Service Provider Interface.
+     * 
+     * @param algorithm
+     * @param service
+     * @throws NoSuchAlgorithmException
+     */
+    public synchronized void getInstance(String algorithm, Object param)
+            throws NoSuchAlgorithmException {
+        Provider.Service serv;
+
+        if (algorithm == null) {
+            throw new NoSuchAlgorithmException(Messages.getString("security.149")); //$NON-NLS-1$
+        }
+        Services.refresh();
+        if (returnedService != null
+                && algorithm.equalsIgnoreCase(lastAlgorithm)
+                && refreshNumber == Services.refreshNumber) {
+            serv = returnedService;
+        } else {
+            if (Services.isEmpty()) {
+                throw new NoSuchAlgorithmException(Messages.getString("security.14A", //$NON-NLS-1$
+                        serviceName, algorithm));
+            }
+            serv = Services.getService(new StringBuffer(128)
+                    .append(serviceName).append(".").append( //$NON-NLS-1$
+                            algorithm.toUpperCase()).toString());
+            if (serv == null) {
+                throw new NoSuchAlgorithmException(Messages.getString("security.14A", //$NON-NLS-1$
+                        serviceName, algorithm));
+            }
+            returnedService = serv;
+            lastAlgorithm = algorithm;
+            refreshNumber = Services.refreshNumber;
+        }
+        spi = serv.newInstance(param);
+        this.provider = serv.getProvider();
+    }
+
+    /**
+     * 
+     * Finds the appropriate service implementation and creates instance of the
+     * class that implements corresponding Service Provider Interface.
+     * 
+     * @param algorithm
+     * @param service
+     * @param provider
+     * @throws NoSuchAlgorithmException
+     */
+    public synchronized void getInstance(String algorithm, Provider provider,
+            Object param) throws NoSuchAlgorithmException {
+
+        Provider.Service serv = null;
+        if (algorithm == null) {
+            throw new NoSuchAlgorithmException(
+                    Messages.getString("security.14B", serviceName)); //$NON-NLS-1$
+        }
+        serv = provider.getService(serviceName, algorithm);
+        if (serv == null) {
+            throw new NoSuchAlgorithmException(Messages.getString("security.14A", //$NON-NLS-1$
+                    serviceName, algorithm));
+        }
+        spi = serv.newInstance(param);
+        this.provider = provider;
+    }
+
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/fortress/PolicyUtils.java b/libcore/security/src/main/java/org/apache/harmony/security/fortress/PolicyUtils.java
new file mode 100644
index 0000000..eda7327
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/fortress/PolicyUtils.java
@@ -0,0 +1,588 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.fortress;
+
+import java.io.File;
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * This class consist of a number of static methods, which provide a common functionality 
+ * for various policy and configuration providers. 
+ * 
+ */
+public class PolicyUtils {
+
+    // No reason to instantiate
+    private PolicyUtils() {}
+    
+    /**
+     * Auxiliary action for opening InputStream from specified location.
+     */
+    public static class URLLoader implements PrivilegedExceptionAction<InputStream> {
+
+        /** 
+         * URL of target location. 
+         */
+        public URL location;
+
+        /**
+         *  Constructor with target URL parameter. 
+         */
+        public URLLoader(URL location) {
+            this.location = location;
+        }
+
+        /** 
+         * Returns InputStream from the target URL.
+         */
+        public InputStream run() throws Exception {
+            return location.openStream();
+        }
+    }
+
+    /** 
+     * Auxiliary action for accessing system properties in a bundle. 
+     */
+    public static class SystemKit implements PrivilegedAction<Properties> {
+
+        /** 
+         * Returns system properties.
+         */
+        public Properties run() {
+            return System.getProperties();
+        }
+    }
+
+    /** 
+     * Auxiliary action for accessing specific system property. 
+     */
+    public static class SystemPropertyAccessor implements PrivilegedAction<String> {
+
+        /** 
+         * A key of a required system property.
+         */
+        public String key;
+
+        /** 
+         * Constructor with a property key parameter. 
+         */
+        public SystemPropertyAccessor(String key) {
+            this.key = key;
+        }
+
+        /** 
+         * Handy one-line replacement of 
+         * &quot;provide key and supply action&quot; code block, 
+         * for reusing existing action instance. 
+         */
+        public PrivilegedAction<String> key(String key) {
+            this.key = key;
+            return this;
+        }
+
+        /** 
+         * Returns specified system property. 
+         */
+        public String run() {
+            return System.getProperty(key);
+        }
+    }
+
+    /** 
+     * Auxiliary action for accessing specific security property. 
+     */
+    public static class SecurityPropertyAccessor implements PrivilegedAction<String> {
+
+        private String key;
+        
+        /** 
+         * Constructor with a property key parameter. 
+         */
+        public SecurityPropertyAccessor(String key) {
+            super();
+            this.key = key;
+        }
+
+        public PrivilegedAction<String> key(String key) {
+            this.key = key;
+            return this;
+        }
+        
+        /** 
+         * Returns specified security property. 
+         */
+        public String run() {
+            return Security.getProperty(key);
+        }
+    }
+    
+    /** 
+     * Auxiliary action for loading a provider by specific security property.
+     */
+    public static class ProviderLoader<T> implements PrivilegedAction<T> {
+
+        private String key;
+        
+        /**
+         * Acceptable provider superclass.
+         */
+        private Class<T> expectedType;
+        
+        /** 
+         * Constructor taking property key and acceptable provider 
+         * superclass parameters.
+         */
+        public ProviderLoader(String key, Class<T> expected) {
+            super();
+            this.key = key;
+            this.expectedType = expected;
+        }
+
+        /** 
+         * Returns provider instance by specified security property.
+         * The <code>key</code> should map to a fully qualified classname.
+         * 
+         * @throws SecurityException if no value specified for the key 
+         * in security properties or if an Exception has occurred 
+         * during classloading and instantiating.
+         */
+        public T run() {
+            String klassName = Security.getProperty(key);
+            if (klassName == null || klassName.length() == 0) {
+                throw new SecurityException(Messages.getString("security.14C", //$NON-NLS-1$
+                                            key));
+            }
+            // TODO accurate classloading
+            try {
+                Class<?> klass = Class.forName(klassName, true,
+                        Thread.currentThread().getContextClassLoader());
+                if (expectedType != null && klass.isAssignableFrom(expectedType)){
+                    throw new SecurityException(Messages.getString("security.14D", //$NON-NLS-1$
+                                              klassName, expectedType.getName()));
+                }
+                //FIXME expectedType.cast(klass.newInstance());
+                return (T)klass.newInstance();
+            }
+            catch (SecurityException se){
+                throw se;
+            }
+            catch (Exception e) {
+                // TODO log error ??
+                SecurityException se = new SecurityException(
+                        Messages.getString("security.14E", klassName)); //$NON-NLS-1$
+                se.initCause(e);
+                throw se;
+            }
+        }
+    }
+
+    /** 
+     * Specific exception to signal that property expansion failed 
+     * due to unknown key. 
+     */
+    public static class ExpansionFailedException extends Exception {
+
+        /**
+         * @serial
+         */
+        private static final long serialVersionUID = 2869748055182612000L;
+
+        /** 
+         * Constructor with user-friendly message parameter. 
+         */
+        public ExpansionFailedException(String message) {
+            super(message);
+        }
+
+        /** 
+         * Constructor with user-friendly message and causing error. 
+         */
+        public ExpansionFailedException(String message, Throwable cause) {
+            super(message, cause);
+        }
+    }
+
+    /**
+     * Substitutes all entries like ${some.key}, found in specified string, 
+     * for specified values.
+     * If some key is unknown, throws ExpansionFailedException. 
+     * @param str the string to be expanded
+     * @param properties available key-value mappings 
+     * @return expanded string
+     * @throws ExpansionFailedException
+     */
+    public static String expand(String str, Properties properties)
+            throws ExpansionFailedException {
+        final String START_MARK = "${"; //$NON-NLS-1$
+        final String END_MARK = "}"; //$NON-NLS-1$
+        final int START_OFFSET = START_MARK.length();
+        final int END_OFFSET = END_MARK.length();
+
+        StringBuilder result = new StringBuilder(str);
+        int start = result.indexOf(START_MARK);
+        while (start >= 0) {
+            int end = result.indexOf(END_MARK, start);
+            if (end >= 0) {
+                String key = result.substring(start + START_OFFSET, end);
+                String value = properties.getProperty(key);
+                if (value != null) {
+                    result.replace(start, end + END_OFFSET, value);
+                    start += value.length();
+                } else {
+                    throw new ExpansionFailedException(Messages.getString("security.14F", key)); //$NON-NLS-1$
+                }
+            }
+            start = result.indexOf(START_MARK, start);
+        }
+        return result.toString();
+    }
+
+    /**
+     * Handy shortcut for 
+     * <code>expand(str, properties).replace(File.separatorChar, '/')</code>.
+     * @see #expand(String, Properties)
+     */
+    public static String expandURL(String str, Properties properties)
+            throws ExpansionFailedException {
+        return expand(str, properties).replace(File.separatorChar, '/');
+    }
+
+    /**
+     * Instances of this interface are intended for resolving  
+     * generalized expansion expressions, of the form ${{protocol:data}}. 
+     * Such functionality is applicable to security policy files, for example.
+     * @see #expandGeneral(String, GeneralExpansionHandler)
+     */
+    public static interface GeneralExpansionHandler {
+
+        /**
+         * Resolves general expansion expressions of the form ${{protocol:data}}.
+         * @param protocol denotes type of resolution
+         * @param data data to be resolved, optional (may be null)
+         * @return resolved value, must not be null
+         * @throws PolicyUtils.ExpansionFailedException if expansion is impossible
+         */
+        String resolve(String protocol, String data)
+                throws ExpansionFailedException;
+    }
+
+    /**
+     * Substitutes all entries like ${{protocol:data}}, found in specified string, 
+     * for values resolved by passed handler.
+     * The data part may be empty, and in this case expression 
+     * may have simplified form, as ${{protocol}}.
+     * If some entry cannot be resolved, throws ExpansionFailedException;
+     * @param str the string to be expanded
+     * @param handler the handler to resolve data denoted by protocol  
+     * @return expanded string
+     * @throws ExpansionFailedException
+     */
+    public static String expandGeneral(String str,
+            GeneralExpansionHandler handler) throws ExpansionFailedException {
+        final String START_MARK = "${{"; //$NON-NLS-1$
+        final String END_MARK = "}}"; //$NON-NLS-1$
+        final int START_OFFSET = START_MARK.length();
+        final int END_OFFSET = END_MARK.length();
+
+        StringBuilder result = new StringBuilder(str);
+        int start = result.indexOf(START_MARK);
+        while (start >= 0) {
+            int end = result.indexOf(END_MARK, start);
+            if (end >= 0) {
+                String key = result.substring(start + START_OFFSET, end);
+                int separator = key.indexOf(':');
+                String protocol = (separator >= 0) ? key
+                        .substring(0, separator) : key;
+                String data = (separator >= 0) ? key.substring(separator + 1)
+                        : null;
+                String value = handler.resolve(protocol, data);
+                result.replace(start, end + END_OFFSET, value);
+                start += value.length();
+            }
+            start = result.indexOf(START_MARK, start);
+        }
+        return result.toString();
+    }
+
+    /** 
+     * A key to security properties, deciding whether usage of 
+     * dynamic policy location via system properties is allowed. 
+     * @see #getPolicyURLs(Properties, String, String)
+     */
+    public static final String POLICY_ALLOW_DYNAMIC = "policy.allowSystemProperty"; //$NON-NLS-1$
+
+    /** 
+     * A key to security properties, deciding whether expansion of 
+     * system properties is allowed 
+     * (in security properties values, policy files, etc).
+     * @see #expand(String, Properties) 
+     */
+    public static final String POLICY_EXPAND = "policy.expandProperties"; //$NON-NLS-1$
+
+    /** 
+     * Positive value of switching properties.
+     */
+    public static final String TRUE = "true"; //$NON-NLS-1$
+
+    /** 
+     * Negative value of switching properties.
+     */
+    public static final String FALSE = "false"; //$NON-NLS-1$
+
+    /** 
+     * Returns false if current security settings disable to perform 
+     * properties expansion, true otherwise.
+     * @see #expand(String, Properties)  
+     */
+    public static boolean canExpandProperties() {
+        return !FALSE.equalsIgnoreCase(AccessController
+                .doPrivileged(new SecurityPropertyAccessor(POLICY_EXPAND)));
+    }
+
+    /**
+     * Obtains a list of locations for a policy or configuration provider.
+     * The search algorithm is as follows:
+     * <ol>
+     * <li> Look in security properties for keys of form <code>prefix + n</code>, 
+     * where <i>n</i> is an integer and <i>prefix</i> is a passed parameter. 
+     * Sequence starts with <code>n=1</code>, and keeps incrementing <i>n</i> 
+     * until next key is not found. <br> 
+     * For each obtained key, try to construct an URL instance. On success, 
+     * add the URL to the list; otherwise ignore it.
+     * <li>
+     *         If security settings do not prohibit (through 
+     *         {@link #POLICY_ALLOW_DYNAMIC the &quot;policy.allowSystemProperty&quot; property}) 
+     *         to use additional policy location, read the system property under the 
+     *         passed key parameter. If property exists, it may designate a file or 
+     *         an absolute URL. Thus, first check if there is a file with that name, 
+     *         and if so, convert the pathname to URL. Otherwise, try to instantiate   
+     *         an URL directly. If succeeded, append the URL to the list 
+     * <li>
+     *         If the additional location from the step above was specified to the 
+     *         system via &quot;==&quot; (i.e. starts with '='), discard all URLs above 
+     *         and use this only URL.
+     * </ol> 
+     * <b>Note:</b> all property values (both security and system) related to URLs are
+     * subject to {@link #expand(String, Properties) property expansion}, regardless 
+     * of the &quot;policy.expandProperties&quot; security setting.  
+     * 
+     * @param system system properties
+     * @param systemUrlKey key to additional policy location
+     * @param securityUrlPrefix prefix to numbered locations in security properties
+     * @return array of URLs to provider's configuration files, may be empty.
+     */
+    public static URL[] getPolicyURLs(final Properties system,
+            final String systemUrlKey, final String securityUrlPrefix) {
+
+        final SecurityPropertyAccessor security = new SecurityPropertyAccessor(
+                null);
+        final List<URL> urls = new ArrayList<URL>();
+        boolean dynamicOnly = false;
+        URL dynamicURL = null;
+
+        //first check if policy is set via system properties
+        if (!FALSE.equalsIgnoreCase(AccessController
+                .doPrivileged(security.key(POLICY_ALLOW_DYNAMIC)))) {
+            String location = system.getProperty(systemUrlKey);
+            if (location != null) {
+                if (location.startsWith("=")) { //$NON-NLS-1$
+                    //overrides all other urls
+                    dynamicOnly = true;
+                    location = location.substring(1);
+                }
+                try {
+                    location = expandURL(location, system);
+                    // location can be a file, but we need an url...
+                    final File f = new File(location);
+                    dynamicURL = AccessController
+                            .doPrivileged(new PrivilegedExceptionAction<URL>() {
+
+                                public URL run() throws Exception {
+                                    if (f.exists()) {
+                                        return f.toURI().toURL();
+                                    } else {
+                                        return null;
+                                    }
+                                }
+                            });
+                    if (dynamicURL == null) {
+                        dynamicURL = new URL(location);
+                    }
+                }
+                catch (Exception e) {
+                    // TODO: log error
+                    // System.err.println("Error detecting system policy location: "+e);
+                }
+            }
+        }
+        //next read urls from security.properties 
+        if (!dynamicOnly) {
+            int i = 1;
+            while (true) {
+                String location = AccessController
+                        .doPrivileged(security.key(new StringBuilder(
+                                securityUrlPrefix).append(i++).toString()));
+                if (location == null) {
+                    break;
+                }
+                try {
+                    location = expandURL(location, system);
+                    URL anURL = new URL(location);
+                    if (anURL != null) {
+                        urls.add(anURL);
+                    }
+                }
+                catch (Exception e) {
+                    // TODO: log error
+                    // System.err.println("Error detecting security policy location: "+e);
+                }
+            }
+        }
+        if (dynamicURL != null) {
+            urls.add(dynamicURL);
+        }
+        return urls.toArray(new URL[urls.size()]);
+    }
+
+    /** 
+     * Converts common-purpose collection of Permissions to PermissionCollection.
+     *
+     * @param perms a collection containing arbitrary permissions, may be null
+     * @return mutable heterogeneous PermissionCollection containing all Permissions 
+     * from the specified collection
+     */
+    public static PermissionCollection toPermissionCollection(
+            Collection<Permission> perms) {
+        Permissions pc = new Permissions();
+        if (perms != null) {
+            for (Iterator<Permission> iter = perms.iterator(); iter.hasNext();) {
+                Permission element = iter.next();
+                pc.add(element);
+            }
+        }
+        return pc;
+    }
+
+    // Empty set of arguments to default constructor of a Permission.
+    private static final Class[] NO_ARGS = {};
+
+    // One-arg set of arguments to default constructor of a Permission.
+    private static final Class[] ONE_ARGS = { String.class };
+
+    // Two-args set of arguments to default constructor of a Permission.
+    private static final Class[] TWO_ARGS = { String.class, String.class };
+
+    /**
+     * Tries to find a suitable constructor and instantiate a new Permission
+     * with specified parameters.  
+     *
+     * @param targetType class of expected Permission instance
+     * @param targetName name of expected Permission instance
+     * @param targetActions actions of expected Permission instance
+     * @return a new Permission instance
+     * @throws IllegalArgumentException if no suitable constructor found
+     * @throws Exception any exception thrown by Constructor.newInstance()
+     */
+    public static Permission instantiatePermission(Class<?> targetType,
+            String targetName, String targetActions) throws Exception {
+
+        // let's guess the best order for trying constructors
+        Class[][] argTypes = null;
+        Object[][] args = null;
+        if (targetActions != null) {
+            argTypes = new Class[][] { TWO_ARGS, ONE_ARGS, NO_ARGS };
+            args = new Object[][] { { targetName, targetActions },
+                    { targetName }, {} };
+        } else if (targetName != null) {
+            argTypes = new Class[][] { ONE_ARGS, TWO_ARGS, NO_ARGS };
+            args = new Object[][] { { targetName },
+                    { targetName, targetActions }, {} };
+        } else {
+            argTypes = new Class[][] { NO_ARGS, ONE_ARGS, TWO_ARGS };
+            args = new Object[][] { {}, { targetName },
+                    { targetName, targetActions } };
+        }
+
+        // finally try to instantiate actual permission
+        for (int i = 0; i < argTypes.length; i++) {
+            try {
+                Constructor<?> ctor = targetType.getConstructor(argTypes[i]);
+                return (Permission)ctor.newInstance(args[i]);
+            }
+            catch (NoSuchMethodException ignore) {}
+        }
+        throw new IllegalArgumentException(
+                Messages.getString("security.150", targetType));//$NON-NLS-1$
+    }
+
+    /**
+     * Checks whether the objects from <code>what</code> array are all
+     * presented in <code>where</code> array.
+     * 
+     * @param what first array, may be <code>null</code> 
+     * @param where  second array, may be <code>null</code>
+     * @return <code>true</code> if the first array is <code>null</code>
+     * or if each and every object (ignoring null values) 
+     * from the first array has a twin in the second array; <code>false</code> otherwise
+     */
+    public static boolean matchSubset(Object[] what, Object[] where) {
+        if (what == null) {
+            return true;
+        }
+
+        for (int i = 0; i < what.length; i++) {
+            if (what[i] != null) {
+                if (where == null) {
+                    return false;
+                }
+                boolean found = false;
+                for (int j = 0; j < where.length; j++) {
+                    if (what[i].equals(where[j])) {
+                        found = true;
+                        break;
+                    }
+                }
+                if (!found) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/fortress/SecurityAccess.java b/libcore/security/src/main/java/org/apache/harmony/security/fortress/SecurityAccess.java
new file mode 100644
index 0000000..7f5055a
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/fortress/SecurityAccess.java
@@ -0,0 +1,54 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris V. Kuznetsov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.fortress;
+
+import java.util.Iterator;
+import java.security.Provider;
+
+/**
+ *
+ * This interface provides access to package visible api in java.security
+ * 
+ */
+public interface SecurityAccess {
+    /**
+     * Access to Security.renumProviders()
+     *
+     */
+    public void renumProviders();
+    
+    /**
+     * Access to Service.getAliases()
+     * @param s
+     * @return
+     */
+    public Iterator<String> getAliases(Provider.Service s);
+    
+    /**
+     * Access to Provider.getService(String type)
+     * @param p
+     * @param type
+     * @return
+     */
+    public Provider.Service getService(Provider p, String type);
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/fortress/SecurityUtils.java b/libcore/security/src/main/java/org/apache/harmony/security/fortress/SecurityUtils.java
new file mode 100644
index 0000000..c2e8f33
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/fortress/SecurityUtils.java
@@ -0,0 +1,115 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Astapchuk
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.fortress;
+
+import java.security.AccessControlContext;
+import java.util.WeakHashMap;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+//FIXME: move this class under umbrella of protected packages -
+// see lib/java.security: property 'package.access',
+// so only trusted classes like Thread and AccessController will
+// have an access to this class. 
+// This is to remove dependency on VMStack, to reduce number 
+// of VM2API-dependent classes.
+
+/**
+ * The class is used to perform an exchange of information between 
+ * java.lang.Thread and java.security.AccessController.<br>
+ * The data to exchange is inherited contexts for the Thread-s.  
+ * 
+ */
+public final class SecurityUtils {
+
+    // A map used to store inherited contexts.<br>
+    // A thread is used as a key for the map and AccessControlContext 
+    // passed to the putContext is used as a value.
+    private static final WeakHashMap<Thread, AccessControlContext> ACC_CACHE = 
+            new WeakHashMap<Thread, AccessControlContext>();
+
+    /**
+     * This method to be invoked in the Thread's constructor. The first argument
+     * (thread) must be Thread's this and the second must be a snapshot of the
+     * current AccessControlContext:
+     * <p>
+     * <code>
+     * Thread() {<br>
+     * SecurityUtils.putContext(this,AccessController.getContext());<br>
+     *  ...do the stuff you need...<br>
+     * }<br>
+     * </code>
+     *
+     * The method throws SecurityException if the method is called more than 
+     * once for a given thread. The first call to <code>putContext</code> is
+     * always performed in the Thread's constructor so this effectively means
+     * that no one can replace the snapshot taken.
+     * 
+     * @throws SecurityException if a context for the passed 
+     *     <code>thread</code> already exists in the map.
+     * @throws NullPointerException if thread is null
+     * @throws Error if context is null AND if null context is already stored 
+     *     in the map 
+     */
+    public static void putContext(Thread thread, AccessControlContext context)
+            throws SecurityException {
+        if (thread == null) {
+            throw new NullPointerException(Messages.getString("security.140")); //$NON-NLS-1$
+        }
+        synchronized (ACC_CACHE) {
+            if (ACC_CACHE.containsKey(thread)) {
+                throw new SecurityException(Messages.getString("security.141")); //$NON-NLS-1$
+            }
+            if (context == null) {
+                // this only allowed once - for the very first thread.
+                if (ACC_CACHE.containsValue(null)) {
+                    throw new Error(Messages.getString("security.142")); //$NON-NLS-1$
+                }
+            }
+            ACC_CACHE.put(thread, context);
+        }
+    }
+
+    /**
+     * Returns the AccessControlContext stored for a given thread.<br>
+     * The method may return null - for the very first thread created 
+     * by the VM which does not have inherited context.<br>
+     * It may also return null if no Thread found in the map - that seems 
+     * possible during VM startup process.
+     */
+    public static AccessControlContext getContext(Thread thread)
+            throws SecurityException {
+
+        // ~fixme: see 'fixme' at the top of the file
+        /*
+         Class cl = VMStack.getCallerClass(0);
+         if (cl != AccessController.class) {
+         throw new SecurityException("You ["+cl+"] do not have access to this resource.");
+         }
+         */
+
+        synchronized (ACC_CACHE) {
+            return ACC_CACHE.get(thread);
+        }
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/fortress/Services.java b/libcore/security/src/main/java/org/apache/harmony/security/fortress/Services.java
new file mode 100644
index 0000000..2e92d82
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/fortress/Services.java
@@ -0,0 +1,252 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris V. Kuznetsov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.fortress;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ * This class contains information about all registered providers and preferred
+ * implementations for all "serviceName.algName".
+ * 
+ */
+
+public class Services {
+
+    // The HashMap that contains information about preferred implementations for
+    // all serviceName.algName in the registered providers
+    private static final Map<String, Provider.Service> services = new HashMap<String, Provider.Service>(512);
+
+    // Need refresh flag
+    private static boolean needRefresh; // = false;
+
+    /**
+     * Refresh number
+     */
+    public static int refreshNumber = 1;
+
+    // Registered providers
+    private static final List<Provider> providers = new ArrayList<Provider>(20);
+
+    // Hash for quick provider access by name
+    private static final Map<String, Provider> providersNames = new HashMap<String, Provider>(20);
+
+    static {
+        AccessController.doPrivileged(new PrivilegedAction<Object>() {
+            public Object run() {
+                loadProviders();
+                return null;
+            }
+        });
+    }
+
+    // Load statically registered providers and init Services Info
+    private static void loadProviders() {
+        String providerClassName = null;
+        int i = 1;
+        ClassLoader cl = ClassLoader.getSystemClassLoader();
+        Provider p;
+
+        while ((providerClassName = Security.getProperty("security.provider." //$NON-NLS-1$
+                + i++)) != null) {
+            try {
+                p = (Provider) Class
+                        .forName(providerClassName.trim(), true, cl)
+                        .newInstance();
+                providers.add(p);
+                providersNames.put(p.getName(), p);
+                initServiceInfo(p);
+            } catch (Exception e) { // ignore
+            }
+        }
+        Engine.door.renumProviders();
+    }
+
+    /**
+     * Returns registered providers
+     * 
+     * @return
+     */
+    public static Provider[] getProviders() {
+        return providers.toArray(new Provider[providers.size()]);
+    }
+
+    /**
+     * Returns registered providers as List
+     * 
+     * @return
+     */
+    public static List<Provider> getProvidersList() {
+        return new ArrayList<Provider>(providers);
+    }
+
+    /**
+     * Returns the provider with the specified name
+     * 
+     * @param name
+     * @return
+     */
+    public static Provider getProvider(String name) {
+        if (name == null) {
+            return null;
+        }
+        return providersNames.get(name);
+    }
+
+    /**
+     * Inserts a provider at a specified position
+     * 
+     * @param provider
+     * @param position
+     * @return
+     */
+    public static int insertProviderAt(Provider provider, int position) {
+        int size = providers.size();
+        if ((position < 1) || (position > size)) {
+            position = size + 1;
+        }
+        providers.add(position - 1, provider);
+        providersNames.put(provider.getName(), provider);
+        setNeedRefresh();
+        return position;
+    }
+
+    /**
+     * Removes the provider
+     * 
+     * @param providerNumber
+     */
+    public static void removeProvider(int providerNumber) {
+        Provider p = providers.remove(providerNumber - 1);
+        providersNames.remove(p.getName());
+        setNeedRefresh();
+    }
+
+    /**
+     * 
+     * Adds information about provider services into HashMap.
+     * 
+     * @param p
+     */
+    public static void initServiceInfo(Provider p) {
+        Provider.Service serv;
+        String key;
+        String type;
+        String alias;
+        StringBuffer sb = new StringBuffer(128);
+
+        for (Iterator<Provider.Service> it1 = p.getServices().iterator(); it1.hasNext();) {
+            serv = it1.next();
+            type = serv.getType();
+            sb.delete(0, sb.length());
+            key = sb.append(type).append(".").append( //$NON-NLS-1$
+                    serv.getAlgorithm().toUpperCase()).toString();
+            if (!services.containsKey(key)) {
+                services.put(key, serv);
+            }
+            for (Iterator<String> it2 = Engine.door.getAliases(serv); it2.hasNext();) {
+                alias = it2.next();
+                sb.delete(0, sb.length());
+                key = sb.append(type).append(".").append(alias.toUpperCase()) //$NON-NLS-1$
+                        .toString();
+                if (!services.containsKey(key)) {
+                    services.put(key, serv);
+                }
+            }
+        }
+    }
+
+    /**
+     * 
+     * Updates services hashtable for all registered providers
+     *  
+     */
+    public static void updateServiceInfo() {
+        services.clear();
+        for (Iterator<Provider> it = providers.iterator(); it.hasNext();) {
+            initServiceInfo(it.next());
+        }
+        needRefresh = false;
+    }
+
+    /**
+     * Returns true if services contain any provider information  
+     * @return
+     */
+    public static boolean isEmpty() {
+        return services.isEmpty();
+    }
+    
+    /**
+     * 
+     * Returns service description.
+     * Call refresh() before.
+     * 
+     * @param key
+     * @return
+     */
+    public static Provider.Service getService(String key) {
+        return services.get(key);
+    }
+
+    /**
+     * Prints Services content  
+     */
+    // FIXME remove debug function
+    public static void printServices() {
+        refresh();
+        Set<String> s = services.keySet();
+        for (Iterator<String> i = s.iterator(); i.hasNext();) {
+            String key = i.next();
+            System.out.println(key + "=" + services.get(key)); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Set flag needRefresh 
+     *
+     */
+    public static void setNeedRefresh() {
+        needRefresh = true;
+    }
+
+    /**
+     * Refresh services info
+     *
+     */
+    public static void refresh() {
+        if (needRefresh) {
+            refreshNumber++;
+            updateServiceInfo();
+        }
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/internal/nls/Messages.java b/libcore/security/src/main/java/org/apache/harmony/security/internal/nls/Messages.java
new file mode 100644
index 0000000..0c32fba
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/internal/nls/Messages.java
@@ -0,0 +1,124 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * THE FILE HAS BEEN AUTOGENERATED BY MSGTOOL TOOL.
+ * All changes made to this file manually will be overwritten 
+ * if this tool runs again. Better make changes in the template file.
+ */
+
+package org.apache.harmony.security.internal.nls;
+
+import org.apache.harmony.luni.util.MsgHelp;
+
+/**
+ * This class retrieves strings from a resource bundle and returns them,
+ * formatting them with MessageFormat when required.
+ * <p>
+ * It is used by the system classes to provide national language support, by
+ * looking up messages in the <code>
+ *    org.apache.harmony.security.internal.nls.messages
+ * </code>
+ * resource bundle. Note that if this file is not available, or an invalid key
+ * is looked up, or resource bundle support is not available, the key itself
+ * will be returned as the associated message. This means that the <em>KEY</em>
+ * should a reasonable human-readable (english) string.
+ * 
+ */
+public class Messages {
+
+    private static final String sResource =
+        "org.apache.harmony.security.internal.nls.messages"; //$NON-NLS-1$
+
+    /**
+     * Retrieves a message which has no arguments.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg) {
+        return MsgHelp.getString(sResource, msg);
+    }
+
+    /**
+     * Retrieves a message which takes 1 argument.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @param arg
+     *            Object the object to insert in the formatted output.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg, Object arg) {
+        return getString(msg, new Object[] { arg });
+    }
+
+    /**
+     * Retrieves a message which takes 1 integer argument.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @param arg
+     *            int the integer to insert in the formatted output.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg, int arg) {
+        return getString(msg, new Object[] { Integer.toString(arg) });
+    }
+
+    /**
+     * Retrieves a message which takes 1 character argument.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @param arg
+     *            char the character to insert in the formatted output.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg, char arg) {
+        return getString(msg, new Object[] { String.valueOf(arg) });
+    }
+
+    /**
+     * Retrieves a message which takes 2 arguments.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @param arg1
+     *            Object an object to insert in the formatted output.
+     * @param arg2
+     *            Object another object to insert in the formatted output.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg, Object arg1, Object arg2) {
+        return getString(msg, new Object[] { arg1, arg2 });
+    }
+
+    /**
+     * Retrieves a message which takes several arguments.
+     * 
+     * @param msg
+     *            String the key to look up.
+     * @param args
+     *            Object[] the objects to insert in the formatted output.
+     * @return String the message for that key in the system message bundle.
+     */
+    static public String getString(String msg, Object[] args) {
+        return MsgHelp.getString(sResource, msg, args);
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/internal/nls/messages.properties b/libcore/security/src/main/java/org/apache/harmony/security/internal/nls/messages.properties
new file mode 100644
index 0000000..9a73b51
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/internal/nls/messages.properties
@@ -0,0 +1,344 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#  
+#      http://www.apache.org/licenses/LICENSE-2.0
+#  
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+# 
+
+# messages for EN locale
+security.01=Algorithm is null
+security.02=Provider is null or empty string
+security.03=Provider {0} is not available
+security.04=Provider is null
+security.05=Incorrect offset/len parameters
+security.06=Null input parameter
+security.07=the type parameter is null
+security.08=the algorithm parameter is null
+security.09=the format parameter is null
+security.0A=the encoded parameter is null
+security.0B=Could not create SecretKeySpec: {0}
+security.0C=unrecognized type/format combination: {0}/{1}
+security.0D=Could not resolute key: {0}
+security.0E=unrecognized key type: {0}
+security.0F=timestamp cannot be null
+security.10=signerCertPath cannot be null
+security.100=ASN.1 implicitly tagged type is expected at [{0}]. Expected tag: {1}, but encountered tag {2}
+security.101=ASN.1 type:{0} is not designed to be encoded
+security.102=Negative tag number
+security.103=Wrong tag class
+security.104=Tag long form is not implemented
+security.105=DER: only definite length encoding MUST be used
+security.106=ASN.1 bitstring: constructed identifier at [{0}]. Not valid for DER.
+security.107=ASN.1 bitstring: wrong content at [{0}]. DER requires zero unused bits in final octet.
+security.108=ASN.1 boolean: wrong content at [{0}]. DER allows only 0x00 or 0xFF values
+security.109=ASN.1 octetstring: constructed identifier at [{0}]. Not valid for DER.
+security.10A=ASN.1 string: constructed identifier at [{0}]. Not valid for DER.
+security.10B=ASN.1 UTCTime: constructed identifier at [{0}]. Not valid for DER.
+security.10C=ASN.1 UTCTime: wrong format for DER, identifier at [{0}]
+security.10D=ASN.1 GeneralizedTime: constructed identifier at [{0}]. Not valid for DER.
+security.10E=ASN.1 choice type: {0} MUST have at least one alternative
+security.10F=ASN.1 choice type: {0} MUST have alternatives with distinct tags
+security.11={0} {1} implementation not found: {2}
+security.110=Failed to decode ASN.1 choice type.  No alternatives were found for {0}
+security.111=Wrong content length
+security.112=Decoding indefined length encoding is not provided
+security.113=Too long encoding at [{0}]
+security.114=ASN.1 Bitstring: wrong length. Tag at [{0}]
+security.115=ASN.1 Bitstring: wrong content at [{0}]. A number of unused bits MUST be in range 0 to 7
+security.116=ASN.1 Bitstring: wrong content at [{0}]. For empty string unused bits MUST be 0
+security.117=Decoding constructed ASN.1 bitstring  type is not provided
+security.118=ASN.1 bitstring identifier is expected at [{0}], but encountered: {1}
+security.119=ASN.1 enumerated identifier is expected at [{0}], but encountered: {1}
+security.11A=ASN.1 enumerated: wrong length for identifier at [{0}]
+security.11B=ASN.1 enumerated: wrong content at [{0}]. An integer MUST be encoded in minimum number of octets
+security.11C=ASN.1 boolean identifier is expected at [{0}], but encountered:{1} 
+security.11D=Wrong length for ASN.1 boolean at [{0}]
+security.11E=ASN.1 GeneralizedTime: encoded format is not implemented
+security.11F=ASN.1 GeneralizedTime wrongly encoded at [{0}]
+security.12={0}: service cannot use the parameter
+security.120=Decoding constructed ASN.1 GeneralizedTime type is not provided
+security.121=ASN.1 GeneralizedTime identifier is expected at [{0}], but encountered: {1}
+security.122=ASN.1 UTCTime: local time format is not supported.
+security.123=ASN.1 UTCTime: wrong length, identifier at [{0}]
+security.124=Decoding constructed ASN.1 UTCTime type is not provided
+security.125=ASN.1 UTCTime identifier is expected at [{0}], but encountered: {1}
+security.126=Time encoding has invalid char
+security.127=ASN.1 integer identifier is expected at [{0}], but encountered: {1}
+security.128=Wrong length for ASN.1 integer at [{0}]
+security.129=Wrong content for ASN.1 integer at [{0}]. An integer MUST be encoded in minimum number of octets
+security.12A=Decoding constructed ASN.1 octet string  type is not provided
+security.12B=ASN.1 octetstring identifier is expected at [{0}], but encountered: {1}
+security.12C=ASN.1 OID identifier is expected at [{0}], but encountered: {1}
+security.12D=Wrong length for ASN.1 object identifier at [{0}]
+security.12E=Wrong encoding at [{0}]
+security.12F=ASN.1 sequence identifier is expected at [{0}], but encountered: {1}
+security.13=Cert's public key does not match Identity's public key
+security.130=ASN.1 Sequence: mandatory value is missing at [{0}]
+security.131=Mandatory value is missing at [{0}]
+security.132=ASN.1 Sequence: mandatory value is missing at [{0}]
+security.133=Mandatory value is missing at [{0}]
+security.134=Wrong encoding at [{0}]. Content's length and encoded length are not the same
+security.135=ASN.1 sequenceOf identifier is expected at [{0}], but encountered: {1}
+security.136=ASN.1 set identifier is expected at [{0}], but encountered: {1}
+security.137=Decoding ASN.1 Set type is not provided
+security.138=ASN.1 setOf identifier is expected at [{0}], but encountered: {1}
+security.139=Decoding constructed ASN.1 string type is not provided
+security.13A=ASN.1 string type identifier is expected at [{0}], but encountered: {1}
+security.13B=Unexpected end of encoding
+security.13C=Failed to read encoded content
+security.13D=Number of unused bits MUST be in range 0-7
+security.13E=For empty bit string unused bits MUST be 0
+security.13F=ASN.1 explicitly tagged type is expected at [{0}]. Expected tag: {1}, but encountered tag {2}
+security.14=key already used in scope
+security.140=thread can not be null
+security.141=You can not modify this map.
+security.142=null context may be stored only once.
+security.143=Error expanding alias : {0}
+security.144=Self protocol is valid only in context of Principal-based grant entries
+security.145=Unknown expansion protocol : {0}
+security.146=No KeyStore to resolve signers : "{0}"
+security.147=No KeyStore to resolve principal by alias : "{0}"
+security.148=Invalid certificate for alias "{0}" : {1}. Only X509Certificate should be aliased to principals.
+security.149=Null algorithm name
+security.14A={0} {1} implementation not found
+security.14B={0} , algorithm is null
+security.14C=Provider implementation should be specified via "{0}" security property
+security.14D=Provided class {0} does not implement {1}
+security.14E=Unable to instantiate provider : {0}
+security.14F=Unknown key: {0}
+security.15=collection is read-only
+security.150=No suitable constructors found in permission class : {0}. Zero, one or two-argument constructor is expected
+security.151=Certificate Factory supports CRLs and Certificates in (PEM) ASN.1 DER encoded form, and Certification Paths in PkiPath and PKCS7 formats.
+security.152=Input Stream contains not enough data.
+security.153=Input stream should not be null.
+security.154=Invalid PKCS7 data provided
+security.155=There is no data in the stream.
+security.156=Incorrect PEM encoding: EOF before content.
+security.157=Incorrect Base64 encoding: EOF without closing delimiter.
+security.158=Incorrect Base64 encoding: New line code is expected before closing delimiter boundary.
+security.159=Incorrect Base64 encoding.
+security.15A=Could not reset the stream: position became invalid or stream has not been marked.
+security.15B=Incorrect PEM encoding: '-----BEGIN{0}' is expected as opening delimiter boundary.
+security.15B1=Incorrect PEM encoding: '-----END{0}' is expected as closing delimiter boundary.
+security.15B2=Incorrect PEM encoding: New line code is expected after the opening delimiter boundary."
+security.15B3=Bad Certificate encoding.
+security.15B4=Bad CRL encoding.
+security.15C=Signature was not verified.
+security.15D=One of provided certificates is not X509 certificate
+security.15E=Incorrect encoded form: {0}
+security.15F=Unsupported encoding.
+security.16=invalid permission: {0}
+security.160=Incorrect PKCS7 encoded form: missing signed data
+security.161=Encoding Error occurred
+security.162=null is passed to 'buf' parameter
+security.163=buf.lendth doesn't fit supplied offset and len
+security.164=\ len < digest's length (which is 20 bytes) 
+security.165=negative offset: {0}
+security.166=no byte[] passed to 'input' parameter
+security.167=input.lendth doesn't fit supplied offset and len
+security.168='privateKey' is not instanceof DSAPrivateKey
+security.169=bad p
+security.16A=bad q
+security.16B=x is not positive or >= q
+security.16C='publicKey' is not instanceof DSAPublicKey
+security.16D=y is not positive
+security.16E=invalid parameter for this engine
+security.16F=signature bytes have invalid encoding
+security.17=no more elements
+security.170=bad argument: byte[] is too small
+security.171=numBytes={0}
+security.172=OID's group is null
+security.173=No SignedData found
+security.174=Can not recognize a critical extension
+security.175=Incorrect MD
+security.176=Incorrect signature
+security.177=Illegal format: 
+security.178=Unrecognizable attribute name: {0}
+security.179=AttributeValue getDecodedObject MUST not be invoked
+security.17A=AttributeValue encodeContent MUST not be invoked
+security.17B=ObjectIdentifier: invalid static initialization - duplicate OIDs:{0}, {1}
+security.17C=ObjectIdentifier: invalid static initialization - small OID pool capacity
+security.17D=permittedSubtrees are empty
+security.17E=excludedSubtrees are empty
+security.17F=DistributionPoint MUST NOT consist of only the reasons field
+security.18=Could not store certificate
+security.180=Unknown string representation for type [{0}]
+security.181=Unknown type: [{0}]
+security.182=Specified iPAddress is not correct.
+security.183=GeneralName: unknown tag: {0}
+security.184=DNS name must start with a letter:'{0}' {1} 
+security.185=Incorrect DNS name: {0}
+security.186=Incorrect DNS name: label ends with '-': {0}
+security.187=Bad representation of uniformResourceIdentifier. It must include the scheme and a scheme-specific-part: {0}
+security.188=Bad representation of uniformResourceIdentifier. It should not be relative: {0}
+security.189=Bad representation of uniformResourceIdentifier.{0}
+security.18A=OID should consist of no less than 2 components:{0}
+security.18B=Component of IPv4 address should consist of no more than 3 decimal numbers: {0}
+security.18C=Incorrect IP representation: {0}
+security.18D=IPv4 address should consist of 4 decimal numbers: {0}
+security.18E=Incorrect IPv6 representation: '{0}'
+security.18F=IPv6 address should consist of 8 hexadecimal numbers: {0}
+security.19=Could not find CertificateFactory of type {0}
+security.190=GeneralName: scheme is missing in URI: {0}
+security.191=GeneralName: unknown tag: {0}
+security.192=Invalid distinguished name string
+security.193=ATTENTION: 'bytesRead == -1' in getLinuxRandomBits()
+security.194=ATTENTION: IOException in RandomBitsSupplier.getLinuxRandomBits()\n
+security.195=numBytes <= 0  : {0}
+security.196=ATTENTION: service is not available : no random devices
+security.197=ATTENTION: service is not available : native library is not linked
+security.198=ATTENTION: getWindowsRandom(myBytes, numBytes) returned false
+security.199={0} {1} implementation not found: 
+security.1A=Could not generate certificate
+security.1B=The value of len parameter is less than the actual digest length.
+security.1C=Invalid negative offset
+security.1D=Incorrect offset or len value
+security.1E=Parameter has already been initialized
+security.1F=Parameter has not been initialized
+security.20=invalid null permission
+security.21=Null permission
+security.22=collection is corrupted
+security.23=all-enabled flag is corrupted
+security.24=Inconsistent types of contained permissions
+security.25=Invalid state of wildcard flag
+security.26=The public key in the certificate cannot be used for digital signature purposes
+security.27=Signature object is not initialized properly.
+security.28=name must not be null
+security.29=name must not be empty
+security.2D=The value of len parameter is less than the actual signature length
+security.2E=Method initialize(AlgorithmParameterSpec params, SecureRandom random)is not supported
+security.2F=type cannot be null
+security.2A=The filter is null
+security.2B=The filter is not in the required format
+security.2C=The key is null
+security.30=Cannot encode certificate {0}
+security.31=target type field is corrupted
+security.32=Error decoding certificate
+security.33=Not Supported operation
+security.35=protectionParameter is neither PasswordProtection nor CallbackHandlerProtection instance
+security.36=Password was destroyed
+security.37=ProtectionParameter object is not PasswordProtection: {0}
+security.38=Unknown KeyStore.Entry object
+security.39=entry is null
+security.3A=protParam should be PasswordProtection or CallbackHandlerProtection
+security.3B=Entry object is neither PrivateKeyObject nor SecretKeyEntrynor TrustedCertificateEntry:  {0}
+security.3C=Incorrect ProtectionParameter
+security.3D=Default CallbackHandler was not defined
+security.3E=LoadSroreParameter is null
+security.3F=alias is null
+security.40=entryClass is null
+security.41=keystore is null
+security.41=the keyStore parameter is null
+security.42=protectionParameter is null
+security.43=file is null
+security.44=File: {0} does not exist
+security.45={0} does not refer to a normal file
+security.46=getKeyStore() was not invoked
+security.47=handler is null
+security.48=privateKey is null
+security.49=chain is null
+security.4A=chain length equals 0
+security.4B=Algorithm of private key does not match algorithm of public key in end certificate of entry (with index number: 0)
+security.4C=Certificates from the given chain have different types
+security.4D=secretKey is null
+security.4E=trustCertificate is null
+security.4F=KeyStore was not initialized
+security.50=password is null
+security.51=stream is null
+security.52=Certificate chain is not defined for Private key 
+security.53=Index should be -1 when CertPath is null
+security.54=Invalid index
+security.55=the certPath parameter is null
+security.56=The OID: "{0}" is incorrect.
+security.57=The name component is not a Stirng or a byte array.
+security.58=pathLen criteria should be >= -2
+security.59=Failed to get X500Principal issuer
+security.5A=Failed to get X500Principal subject
+security.5B=the maxPathLength parameter is less than -1
+security.5C=the trustedCert parameter is null
+security.5D=the caName parameter is null
+security.5E=the caPublicKey parameter is null
+security.5F=the caName parameter is empty string
+security.60=the caPrincipal parameter is null
+security.62=The name is not a String or byte array
+security.61=issuer
+security.63=Provided parameter is null
+security.64=the trustAnchor parameter is null
+security.65=the subjectPublicKey parameter is null
+security.66=Could not create serialization object:{0}
+security.67=Could not resolve cert path: {0}
+security.68=Could not resolve certificate: {0}
+security.69=the encoded length is 0
+security.6A=the keystore is empty
+security.6B=all list elements must be of type java.security.cert.CertStore
+security.6C=all set elements must be of type java.lang.String
+security.6D=the trust anchors set is empty
+security.6E=all set elements must be of type java.security.cert.TrustAnchor
+security.6F=the trustAnchors parameter is null
+security.70=Method engineGenerateCertPath(InputStream inStream) is not supported
+security.71=Method engineGenerateCertPath(InputStream inStream, String encoding) is not supported
+security.72=Method engineGenerateCertPath(List certificates) is not supported
+security.73=Method engineGetCertPathEncodings() is not supported
+security.74=There are no CertPath encodings
+security.75=the m is not positive
+security.76=the rp is null
+security.77=the rp is invalid
+security.78=the length of ks is invalid
+security.79=the ks is invalid
+security.7A=the field parameter is null
+security.7B=the a parameter is null
+security.7C=the b parameter is null
+security.7D=the a is not in the field
+security.7E=the b is not in the field
+security.7F=invalid saltLen
+security.80=the mdName parameter is null
+security.81=mgfName is null
+security.82=invalid trailerField
+security.83=the {0} parameter is null
+security.84=the w parameter is point at infinity
+security.85=the otherPrimeInfo length is 0
+security.86=the {0} parameter is not positive
+security.87=The stream should not be null
+security.88=The data should not be null
+security.89=Expected entries are : "grant" or "keystore"
+security.8A=Expected syntax is : keystore "url"[, "type"]
+security.8B=Expected syntax is : signedby "name1,...,nameN"
+security.8C=Expected syntax is : codebase "url"
+security.8D=Expected syntax is : principal [class_name] "principal_name"
+security.8E=Expected syntax is : permission permission_class_name ["target_name"] [, "action_list"] [, signedby "name1,...,nameN"]
+security.8F=Unexpected token encountered: {0}. {1}
+security.90=Unexpected token encountered: {0}
+security.91=Class cannot be null or empty
+security.92=identity is null
+security.93=name '{0}' is already used
+security.94=key '{0}' is already used
+security.95=invalid identity's name
+security.96=identity is not found
+security.97=ASN.1 Named Bitstring: size contstrains
+security.98=OID's array is null
+security.99=OID MUST have at least 2 subidentifiers
+security.9A=Valid values for first subidentifier are 0, 1 and 2
+security.9B=If the first subidentifier has 0 or 1 value the second subidentifier value MUST be less then 40. 
+security.9C=Subidentifier MUST have positive value.
+security.9D=ObjectIdentifier string is null
+security.9E=Incorrect syntax
+security.9F=Implicit tagging can not be used for ASN.1 ANY or CHOICE type
+security.19A=Failed to decode keySpec encoding: {0}
+security.19B=Failed to decode parameters: {0}
+security.19C='keySpec' is neither DSAPrivateKeySpec nor PKCS8EncodedKeySpec
+security.19D='keySpec' is neither DSAPublicKeySpec nor X509EncodedKeySpec
+security.19E=null is passed to the 'keySpec' argument
+security.19F='key' is neither DSAPublicKey nor DSAPrivateKey
+security.1A0=ATTENTION: InvalidKeySpecException in engineGeneratePrivate: {0}
+security.1A1=ATTENTION: InvalidKeySpecException in engineGeneratePublic: {0}
+security.1A2=Failed to encode issuer name
+security.1A3=AccessDescriptions list is null or empty
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/pkcs10/CertificationRequest.java b/libcore/security/src/main/java/org/apache/harmony/security/pkcs10/CertificationRequest.java
new file mode 100644
index 0000000..84c6734
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/pkcs10/CertificationRequest.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.harmony.security.pkcs10;
+
+import org.apache.harmony.security.asn1.ASN1BitString;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.asn1.BitString;
+import org.apache.harmony.security.x509.AlgorithmIdentifier;
+
+/**
+ * The class implements the ASN.1 DER encoding and decoding of the PKCS#10
+ * Certificate Signing Request (CSR). Its ASN notation is as follows:
+ * 
+ * CertificationRequest ::= SEQUENCE {
+ *   certificationRequestInfo CertificationRequestInfo,
+ *   signatureAlgorithm SignatureAlgorithmIdentifier,
+ *   signature Signature 
+ * }
+ * 
+ * SignatureAlgorithmIdentifier ::= AlgorithmIdentifier
+ * 
+ * Signature ::= BIT STRING
+ */
+public class CertificationRequest {
+    
+    // the value of certificationRequestInfo field of the structure
+    private CertificationRequestInfo info;
+
+    // the value of signatureAlgorithm field of the structure
+    private AlgorithmIdentifier algId;
+
+    // the value of signature field of the structure
+    private byte[] signature;
+
+    // the ASN.1 encoded form of CertificationRequest
+    private byte[] encoding;
+
+    public CertificationRequest(CertificationRequestInfo info,
+            AlgorithmIdentifier algId, byte[] signature) {
+        this.info = info;
+        this.algId = algId;
+        this.signature = new byte[signature.length];
+        System.arraycopy(signature, 0, this.signature, 0, signature.length);
+    }
+    
+    // private constructor with encoding given
+    private CertificationRequest(CertificationRequestInfo info,
+            AlgorithmIdentifier algId, byte[] signature, byte[] encoding) {
+        this(info, algId, signature);
+        this.encoding = encoding;
+    }
+
+    /**
+     * @return Returns the algId.
+     */
+    public AlgorithmIdentifier getAlgId() {
+        return algId;
+    }
+
+    /**
+     * @return Returns the info.
+     */
+    public CertificationRequestInfo getInfo() {
+        return info;
+    }
+
+    /**
+     * @return Returns the signature.
+     */
+    public byte[] getSignature() {
+        byte[] result = new byte[signature.length];
+        System.arraycopy(signature, 0, result, 0, signature.length);
+        return result;
+    }
+
+    /**
+     * Returns ASN.1 encoded form of this CertificationRequest value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = CertificationRequest.ASN1.encode(this);
+        }
+        return encoding;
+    }
+    
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
+            CertificationRequestInfo.ASN1,  // info
+            AlgorithmIdentifier.ASN1,       // signatureAlgorithm
+            ASN1BitString.getInstance() })  // signature
+    {
+
+        public Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+
+            return new CertificationRequest(
+                    (CertificationRequestInfo) values[0],
+                    (AlgorithmIdentifier) values[1],
+                    ((BitString) values[2]).bytes, 
+                    in.getEncoded());
+        }
+
+        protected void getValues(Object object, Object[] values) {
+            CertificationRequest certReq = (CertificationRequest) object;
+
+            values[0] = certReq.info;
+            values[1] = certReq.algId;
+            values[2] = new BitString(certReq.signature, 0);
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/pkcs10/CertificationRequestInfo.java b/libcore/security/src/main/java/org/apache/harmony/security/pkcs10/CertificationRequestInfo.java
new file mode 100644
index 0000000..7c57e93
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/pkcs10/CertificationRequestInfo.java
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.harmony.security.pkcs10;
+
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.asn1.ASN1Implicit;
+import org.apache.harmony.security.asn1.ASN1Integer;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1SetOf;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.x501.AttributeTypeAndValue;
+import org.apache.harmony.security.x501.Name;
+import org.apache.harmony.security.x509.SubjectPublicKeyInfo;
+
+/**
+   CertificationRequestInfo ::= SEQUENCE {
+     version Version,
+     subject Name,
+     subjectPublicKeyInfo SubjectPublicKeyInfo,
+     attributes [0] IMPLICIT Attributes }
+
+   Version ::= INTEGER
+
+   Attributes ::= SET OF Attribute
+*/
+
+public class CertificationRequestInfo {
+    // version 
+    private int version;
+
+    // the value of subject field of the structure
+    private Name subject;
+
+    // the value of subjectPublicKeyInfo field of the structure
+    private SubjectPublicKeyInfo subjectPublicKeyInfo;
+
+    // the value of attributes field of the structure
+    private List attributes;
+    
+    // the ASN.1 encoded form of CertificationRequestInfo
+    private byte [] encoding;
+
+    public CertificationRequestInfo(int version, Name subject,
+            SubjectPublicKeyInfo subjectPublicKeyInfo, List attributes) {
+        this.version = version;
+        this.subject = subject;
+        this.subjectPublicKeyInfo = subjectPublicKeyInfo;
+        this.attributes = attributes;
+    }
+
+    // private constructor with encoding given 
+    private CertificationRequestInfo(int version, Name subject,
+            SubjectPublicKeyInfo subjectPublicKeyInfo, List attributes, byte [] encoding) {
+        this(version, subject, subjectPublicKeyInfo, attributes);
+        this.encoding = encoding;
+    }
+
+    /**
+     * @return Returns the attributes.
+     */
+    public List getAttributes() {
+        return attributes;
+    }
+
+    /**
+     * @return Returns the subject.
+     */
+    public Name getSubject() {
+        return subject;
+    }
+
+    /**
+     * @return Returns the subjectPublicKeyInfo.
+     */
+    public SubjectPublicKeyInfo getSubjectPublicKeyInfo() {
+        return subjectPublicKeyInfo;
+    }
+
+    /**
+     * @return Returns the version.
+     */
+    public int getVersion() {
+        return version;
+    }
+    
+    /**
+     * Returns ASN.1 encoded form of this CertificationRequestInfo.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+
+    public String toString() {
+        StringBuffer res = new StringBuffer();
+        res.append("-- CertificationRequestInfo:"); //$NON-NLS-1$
+        res.append("\n version: "); //$NON-NLS-1$
+        res.append(version);
+        res.append("\n subject: "); //$NON-NLS-1$
+        res.append(subject.getName(X500Principal.CANONICAL));
+        res.append("\n subjectPublicKeyInfo: "); //$NON-NLS-1$
+        res.append("\n\t algorithm: " //$NON-NLS-1$
+                + subjectPublicKeyInfo.getAlgorithmIdentifier().getAlgorithm());
+        res.append("\n\t public key: " + subjectPublicKeyInfo.getPublicKey()); //$NON-NLS-1$
+        res.append("\n attributes: "); //$NON-NLS-1$
+        if (attributes != null) {
+            res.append(attributes.toString());
+        } else {
+            res.append("none"); //$NON-NLS-1$
+        }
+        res.append("\n-- CertificationRequestInfo End\n"); //$NON-NLS-1$
+        return res.toString();
+    }
+
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
+            ASN1Integer.getInstance(),              // version
+            Name.ASN1,                              // subject
+            SubjectPublicKeyInfo.ASN1,              // subjectPublicKeyInfo
+            new ASN1Implicit(0, new ASN1SetOf(
+                    AttributeTypeAndValue.ASN1))    // attributes
+            }) {
+
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+            return new CertificationRequestInfo(
+                    ASN1Integer.toIntValue(values[0]),
+                    (Name) values[1],
+                    (SubjectPublicKeyInfo) values[2],
+                    (List) values[3],
+                    in.getEncoded());
+        }
+        
+        protected void getValues(Object object, Object[] values) {
+            CertificationRequestInfo certReqInfo = (CertificationRequestInfo) object;
+
+            values[0] = ASN1Integer.fromIntValue(certReqInfo.version);
+            values[1] = certReqInfo.subject;
+            values[2] = certReqInfo.subjectPublicKeyInfo;
+            values[3] = certReqInfo.attributes;
+        }
+    };
+
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/pkcs7/AuthenticatedAttributes.java b/libcore/security/src/main/java/org/apache/harmony/security/pkcs7/AuthenticatedAttributes.java
new file mode 100644
index 0000000..b52483f
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/pkcs7/AuthenticatedAttributes.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris Kuznetsov
+* @version $Revision$
+*/
+package org.apache.harmony.security.pkcs7;
+
+import java.util.List;
+
+import org.apache.harmony.security.asn1.ASN1SetOf;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.x501.AttributeTypeAndValue;
+
+/**
+ * 
+ * As defined in PKCS #7: Cryptographic Message Syntax Standard
+ * (http://www.ietf.org/rfc/rfc2315.txt):
+ * authenticatedAttributes is a set of attributes that are signed (i.e., authenticated) by the signer
+ */
+class AuthenticatedAttributes {
+    private byte[] encoding;
+    private List authenticatedAttributes;
+    
+    public AuthenticatedAttributes(byte[] encoding, List authenticatedAttributes) {
+        this.encoding = encoding;
+        this.authenticatedAttributes = authenticatedAttributes;
+    }
+    public List getAttributes() {
+        return authenticatedAttributes;
+    }
+
+    /**
+     * Returns ASN.1 encoded form of this authenticatedAttributes.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    public static final ASN1SetOf ASN1 =
+        new ASN1SetOf(AttributeTypeAndValue.ASN1) {
+        public Object getDecodedObject(BerInputStream in) {
+            return new AuthenticatedAttributes(in.getEncoded(),
+                    (List) in.content);
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/pkcs7/ContentInfo.java b/libcore/security/src/main/java/org/apache/harmony/security/pkcs7/ContentInfo.java
new file mode 100644
index 0000000..0249055
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/pkcs7/ContentInfo.java
@@ -0,0 +1,161 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris Kuznetsov
+* @version $Revision$
+*/
+package org.apache.harmony.security.pkcs7;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.apache.harmony.security.asn1.ASN1Any;
+import org.apache.harmony.security.asn1.ASN1Explicit;
+import org.apache.harmony.security.asn1.ASN1OctetString;
+import org.apache.harmony.security.asn1.ASN1Oid;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+
+/**
+ * As defined in PKCS #7: Cryptographic Message Syntax Standard
+ * (http://www.ietf.org/rfc/rfc2315.txt)
+ * 
+ * ContentInfo ::= SEQUENCE {
+ *       contentType  ContentType,
+ *       content      [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
+ *     }
+ */
+
+public class ContentInfo {
+
+    // OIDs
+    public static final int[] DATA = new int[] {1, 2, 840, 113549, 1, 7, 1};
+    public static final int[] SIGNED_DATA = new int[] {1, 2, 840, 113549, 1, 7, 2};
+    public static final int[] ENVELOPED_DATA = new int[] {1, 2, 840, 113549, 1, 7, 3};
+    public static final int[] SIGNED_AND_ENVELOPED_DATA = new int[] {1, 2, 840, 113549, 1, 7, 4};
+    public static final int[] DIGESTED_DATA = new int[] {1, 2, 840, 113549, 1, 7, 5};
+    public static final int[] ENCRYPTED_DATA = new int[] {1, 2, 840, 113549, 1, 7, 6};
+
+    private int[] oid;
+    private Object content;
+    private byte[] encoding;
+
+    public ContentInfo(int[] oid, Object content) {
+        this.oid = oid;
+        this.content = content;
+    }
+
+    private ContentInfo(int[] oid, Object content, byte[] encoding) {
+        this.oid = oid;
+        this.content = content;
+        this.encoding = encoding;
+    }
+
+    public SignedData getSignedData() {
+        if (Arrays.equals(oid, SIGNED_DATA)) {
+            return (SignedData)content;
+        }
+        return null;
+    }
+
+    public Object getContent() {
+        return content;
+    }
+    
+    public int[] getContentType() {
+        return oid;
+    }
+    
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        // Note: this is internal object and can not be accessible from
+        // public API, so encoding is not copied. The classes which use
+        // this class should copy encoding before passing it out.
+        return encoding;
+    }
+    
+    public String toString() {
+        StringBuffer res = new StringBuffer();
+        res.append("==== ContentInfo:"); //$NON-NLS-1$
+        res.append("\n== ContentType (OID): "); //$NON-NLS-1$
+        for (int i = 0; i< oid.length; i++) {
+            res.append(oid[i]);
+            res.append(' ');
+        }
+        res.append("\n== Content: ");        //$NON-NLS-1$
+        if (content != null) {
+            res.append("\n"); //$NON-NLS-1$
+            res.append(content.toString()); 
+        }    
+        res.append("\n== Content End"); //$NON-NLS-1$
+        res.append("\n==== ContentInfo End\n"); //$NON-NLS-1$
+        return res.toString();
+    }
+
+    public static final ASN1Sequence ASN1 = 
+        new ASN1Sequence(new ASN1Type[] {
+                ASN1Oid.getInstance(),
+                new ASN1Explicit(0, ASN1Any.getInstance())
+                })  {    
+        {
+            setOptional(1); // content is optional
+        }
+        
+        protected void getValues(Object object, Object[] values) {
+            ContentInfo ci = (ContentInfo) object;
+            values[0] = ci.oid;
+            if (ci.content != null) {
+                if (Arrays.equals(ci.oid, DATA)) {
+                    if (ci.content != null) {
+                        values[1] = 
+                            ASN1OctetString.getInstance().encode(ci.content);
+                    }
+                } else if (ci.content instanceof SignedData) {
+                    values[1] = SignedData.ASN1.encode(ci.content);
+                } else {
+                    values[1] = ci.content;
+                }
+            }
+        }
+
+        protected Object getDecodedObject(BerInputStream in) throws IOException {
+            Object[] values = (Object[]) in.content;
+            int[] oid = (int[]) values[0];
+            if (Arrays.equals(oid, DATA)) {
+                if (values[1] != null) {  
+                    return new ContentInfo(oid, 
+                            ASN1OctetString.getInstance().decode((byte[])values[1]),
+                            in.getEncoded());
+                }  else {
+                    return new ContentInfo((int[])values[0], null,
+                            in.getEncoded());
+                }
+            }
+            if (Arrays.equals(oid, SIGNED_DATA)) {
+                return new ContentInfo((int[])values[0],
+                        SignedData.ASN1.decode((byte[])values[1]),
+                        in.getEncoded());
+            }
+            return new ContentInfo((int[])values[0], (byte[])values[1],
+                    in.getEncoded());
+        } 
+   };    
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/pkcs7/SignedData.java b/libcore/security/src/main/java/org/apache/harmony/security/pkcs7/SignedData.java
new file mode 100644
index 0000000..718d3d3
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/pkcs7/SignedData.java
@@ -0,0 +1,166 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris Kuznetsov
+* @version $Revision$
+*/
+package org.apache.harmony.security.pkcs7;
+
+import java.util.List;
+
+import org.apache.harmony.security.asn1.ASN1Any;
+import org.apache.harmony.security.asn1.ASN1Implicit;
+import org.apache.harmony.security.asn1.ASN1Integer;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1SetOf;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.x509.AlgorithmIdentifier;
+import org.apache.harmony.security.x509.Certificate;
+import org.apache.harmony.security.x509.CertificateList;
+
+
+/**
+ * As defined in PKCS #7: Cryptographic Message Syntax Standard
+ * (http://www.ietf.org/rfc/rfc2315.txt)
+ * 
+ * SignedData ::= SEQUENCE { 
+ *   version Version, 
+ *   digestAlgorithms DigestAlgorithmIdentifiers,
+ *   contentInfo ContentInfo,
+ *   certificates
+ *     [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL,
+ *   crls 
+ *     [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+ *   signerInfos SignerInfos }
+ *  
+ */
+
+public class SignedData {
+
+    private int version;
+
+    private List digestAlgorithms;
+    private ContentInfo contentInfo;
+    private List certificates;
+    private List crls;
+    private List signerInfos;
+
+    public SignedData(int version, List digestAlgorithms, ContentInfo contentInfo,
+            List certificates, List crls, List signerInfos) {
+        this.version = version;
+        this.digestAlgorithms = digestAlgorithms;
+        this.contentInfo = contentInfo;
+        this.certificates = certificates;
+        this.crls = crls;
+        this.signerInfos = signerInfos;
+    }
+
+    public List getCertificates() {
+        return certificates;
+    }
+
+    public List getCRLs() {
+        return crls;
+    }
+
+    public List getSignerInfos() {
+        return signerInfos;
+    }
+
+    /**
+     * @return Returns the contentInfo.
+     */
+    public ContentInfo getContentInfo() {
+        return contentInfo;
+    }
+
+    /**
+     * @return Returns the digestAlgorithms.
+     */
+    public List getDigestAlgorithms() {
+        return digestAlgorithms;
+    }
+
+    /**
+     * @return Returns the version.
+     */
+    public int getVersion() {
+        return version;
+    }
+
+    public String toString() {
+        StringBuffer res = new StringBuffer();
+        res.append("---- SignedData:"); //$NON-NLS-1$
+        res.append("\nversion: "); //$NON-NLS-1$
+        res.append(version);
+        res.append("\ndigestAlgorithms: "); //$NON-NLS-1$
+        res.append(digestAlgorithms.toString());
+        res.append("\ncontentInfo: "); //$NON-NLS-1$
+        res.append(contentInfo.toString());
+        res.append("\ncertificates: "); //$NON-NLS-1$
+        if (certificates != null) {
+            res.append(certificates.toString());
+        }
+        res.append("\ncrls: "); //$NON-NLS-1$
+        if (crls != null) {
+            res.append(crls.toString());
+        }
+        res.append("\nsignerInfos:\n"); //$NON-NLS-1$
+        res.append(signerInfos.toString());
+        res.append("\n---- SignedData End\n]"); //$NON-NLS-1$
+        return res.toString();
+    }
+
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
+            ASN1Integer.getInstance(), 
+            new ASN1SetOf(AlgorithmIdentifier.ASN1),
+            ContentInfo.ASN1,
+            new ASN1Implicit(0, new ASN1SetOf(Certificate.ASN1)),
+            new ASN1Implicit(1, new ASN1SetOf(CertificateList.ASN1)),
+            new ASN1SetOf(SignerInfo.ASN1) 
+            }) {
+        {
+            setOptional(3); // certificates is optional
+            setOptional(4); // crls is optional
+        }
+
+        protected void getValues(Object object, Object[] values) {
+            SignedData sd = (SignedData) object;
+            values[0] = new byte[] {(byte)sd.version};
+            values[1] = sd.digestAlgorithms;
+            values[2] = sd.contentInfo;
+            values[3] = sd.certificates;
+            values[4] = sd.crls;
+            values[5] = sd.signerInfos;
+        }
+
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+            return new SignedData(
+                        ASN1Integer.toIntValue(values[0]),
+                        (List) values[1], 
+                        (ContentInfo) values[2],
+                        (List) values[3], 
+                        (List) values[4], 
+                        (List) values[5]
+                    );
+        }
+    };
+
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/pkcs7/SignerInfo.java b/libcore/security/src/main/java/org/apache/harmony/security/pkcs7/SignerInfo.java
new file mode 100644
index 0000000..ea4932d
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/pkcs7/SignerInfo.java
@@ -0,0 +1,222 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris Kuznetsov
+* @version $Revision$
+*/
+package org.apache.harmony.security.pkcs7;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.asn1.ASN1Implicit;
+import org.apache.harmony.security.asn1.ASN1Integer;
+import org.apache.harmony.security.asn1.ASN1OctetString;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1SetOf;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.internal.nls.Messages;
+import org.apache.harmony.security.x501.AttributeTypeAndValue;
+import org.apache.harmony.security.x501.Name;
+import org.apache.harmony.security.x509.AlgorithmIdentifier;
+
+
+/**
+ * As defined in PKCS #7: Cryptographic Message Syntax Standard
+ * (http://www.ietf.org/rfc/rfc2315.txt)
+ * 
+ * SignerInfo ::= SEQUENCE {
+ *   version Version,
+ *   issuerAndSerialNumber IssuerAndSerialNumber,
+ *   digestAlgorithm DigestAlgorithmIdentifier,
+ *   authenticatedAttributes
+ *     [0] IMPLICIT Attributes OPTIONAL,
+ *   digestEncryptionAlgorithm
+ *     DigestEncryptionAlgorithmIdentifier,
+ *   encryptedDigest EncryptedDigest,
+ *   unauthenticatedAttributes
+ *     [1] IMPLICIT Attributes OPTIONAL
+ *  }
+ * 
+ */
+public class SignerInfo {
+
+    private int version;
+    private X500Principal issuer;
+    private BigInteger serialNumber;
+    
+    private AlgorithmIdentifier digestAlgorithm;
+    private AuthenticatedAttributes authenticatedAttributes;
+    private AlgorithmIdentifier digestEncryptionAlgorithm;
+    private byte[] encryptedDigest;
+    private List unauthenticatedAttributes;
+
+    public SignerInfo(int version,
+            Object[] issuerAndSerialNumber,
+            AlgorithmIdentifier digestAlgorithm,
+            AuthenticatedAttributes authenticatedAttributes,
+            AlgorithmIdentifier digestEncryptionAlgorithm,
+            byte[] encryptedDigest,
+            List unauthenticatedAttributes
+            ) {
+        this.version = version;
+        this.issuer = ((Name)issuerAndSerialNumber[0]).getX500Principal();
+// BEGIN android-changed
+        this.serialNumber = ASN1Integer.toBigIntegerValue(issuerAndSerialNumber[1]);
+// END android-changed
+        this.digestAlgorithm = digestAlgorithm;
+        this.authenticatedAttributes = authenticatedAttributes;
+        this.digestEncryptionAlgorithm = digestEncryptionAlgorithm;
+        this.encryptedDigest = encryptedDigest;
+        this.unauthenticatedAttributes = unauthenticatedAttributes;
+    }
+
+    public X500Principal getIssuer() {
+        return issuer;
+    }
+    
+    public BigInteger getSerialNumber() {
+        return serialNumber;
+    }    
+    
+    public String getDigestAlgorithm() {
+        return digestAlgorithm.getAlgorithm();
+    }
+
+    public String getdigestAlgorithm() {
+        return digestAlgorithm.getAlgorithm();
+    }
+
+    public String getDigestEncryptionAlgorithm() {
+        return digestEncryptionAlgorithm.getAlgorithm();
+    }
+
+    public List getAuthenticatedAttributes() {
+        if (authenticatedAttributes == null) {
+            return null;
+        }
+        return authenticatedAttributes.getAttributes();
+    }
+
+    public byte[] getEncodedAuthenticatedAttributes() {
+        if (authenticatedAttributes == null) {
+            return null;
+        }
+        return authenticatedAttributes.getEncoded();
+    }
+
+    public byte[] getEncryptedDigest() {
+        return encryptedDigest;
+    }
+
+    
+    public String toString() {
+        StringBuffer res = new StringBuffer();
+        res.append("-- SignerInfo:"); //$NON-NLS-1$
+        res.append("\n version : "); //$NON-NLS-1$
+        res.append(version);
+        res.append("\nissuerAndSerialNumber:  "); //$NON-NLS-1$
+        res.append(issuer);
+        res.append("   "); //$NON-NLS-1$
+        res.append(serialNumber);
+        res.append("\ndigestAlgorithm:  "); //$NON-NLS-1$
+        res.append(digestAlgorithm.toString());
+        res.append("\nauthenticatedAttributes:  "); //$NON-NLS-1$
+        if (authenticatedAttributes != null) {
+            res.append(authenticatedAttributes.toString());
+        }
+        res.append("\ndigestEncryptionAlgorithm: "); //$NON-NLS-1$
+        res.append(digestEncryptionAlgorithm.toString());
+        res.append("\nunauthenticatedAttributes: "); //$NON-NLS-1$
+        if (unauthenticatedAttributes != null) {
+            res.append(unauthenticatedAttributes.toString());
+        }
+        res.append("\n-- SignerInfo End\n"); //$NON-NLS-1$
+        return res.toString();
+    }
+
+    
+    public static final ASN1Sequence ISSUER_AND_SERIAL_NUMBER = 
+            new ASN1Sequence(new ASN1Type[] { 
+                Name.ASN1,                       // issuer
+                ASN1Integer.getInstance(),       // serialNumber
+            }) 
+        {
+            // method to encode
+            public void getValues(Object object, Object[] values) {
+                Object [] issAndSerial = (Object[])object;
+                values[0] = issAndSerial[0];
+                values[1] = issAndSerial[1];
+        }
+    };
+    
+    public static final ASN1Sequence ASN1 = 
+        new ASN1Sequence(new ASN1Type[] {
+                ASN1Integer.getInstance(),         //version
+                ISSUER_AND_SERIAL_NUMBER,
+                AlgorithmIdentifier.ASN1,           //digestAlgorithm
+                new ASN1Implicit(0, AuthenticatedAttributes.ASN1),//authenticatedAttributes
+                AlgorithmIdentifier.ASN1,            //digestEncryptionAlgorithm
+                ASN1OctetString.getInstance(),       //encryptedDigest
+                 new ASN1Implicit(1, new ASN1SetOf(
+                         AttributeTypeAndValue.ASN1)),//unauthenticatedAttributes
+                })  {
+        {
+            setOptional(3); // authenticatedAttributes is optional
+            setOptional(6); // unauthenticatedAttributes is optional
+        }
+
+        protected void getValues(Object object, Object[] values) {
+            SignerInfo si = (SignerInfo) object;
+            values[0] = new byte[] {(byte)si.version};
+            try {
+                values[1] = new Object[] { new Name(si.issuer.getName()),
+                        si.serialNumber.toByteArray() };
+            } catch (IOException e) {
+                // The exception is never thrown, because si.issuer
+                // is created using Name.getX500Principal(). 
+                // Throw a RuntimeException just to be safe.
+                throw new RuntimeException(
+                        // Msg: "Failed to encode issuer name
+                        Messages.getString("security.1A2"), e);
+            } 
+            values[2] = si.digestAlgorithm;
+            values[3] = si.authenticatedAttributes;
+            values[4] = si.digestEncryptionAlgorithm;
+            values[5] = si.encryptedDigest;
+            values[6] = si.unauthenticatedAttributes;
+        }
+ 
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+            return new SignerInfo(
+                        ASN1Integer.toIntValue(values[0]),
+                        (Object[]) values[1], 
+                        (AlgorithmIdentifier) values[2],
+                        (AuthenticatedAttributes) values[3], 
+                        (AlgorithmIdentifier) values[4], 
+                        (byte[]) values[5],
+                        (List) values[6]
+                    );
+        }
+   };
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/pkcs8/PrivateKeyInfo.java b/libcore/security/src/main/java/org/apache/harmony/security/pkcs8/PrivateKeyInfo.java
new file mode 100644
index 0000000..57afbc0
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/pkcs8/PrivateKeyInfo.java
@@ -0,0 +1,154 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+
+package org.apache.harmony.security.pkcs8;
+
+import org.apache.harmony.security.asn1.ASN1Implicit;
+import org.apache.harmony.security.asn1.ASN1Integer;
+import org.apache.harmony.security.asn1.ASN1OctetString;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1SetOf;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+
+import org.apache.harmony.security.x501.AttributeTypeAndValue;
+
+import org.apache.harmony.security.x509.AlgorithmIdentifier;
+
+import java.util.List;
+
+/**
+ * The class implements the ASN.1 DER encoding and decoding of the PKCS#8
+ * PrivateKeyInfo having the following ASN.1 notation:
+ *
+ *  PrivateKeyInfo ::= SEQUENCE {
+ *      version Version,
+ *      privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ *      privateKey PrivateKey,
+ *      attributes [0] IMPLICIT Attributes OPTIONAL }
+ *
+ *  Version ::= INTEGER
+ *
+ *  PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ *  PrivateKey ::= OCTET STRING
+ *
+ *  Attributes ::= SET OF Attribute
+ */
+
+public class PrivateKeyInfo {
+
+    private int version;
+
+    private AlgorithmIdentifier privateKeyAlgorithm;
+
+    private byte[] privateKey;
+
+    private List attributes;
+
+    private byte[] encoding;
+
+    public PrivateKeyInfo(int version, AlgorithmIdentifier privateKeyAlgorithm,
+            byte[] privateKey, List attributes) {
+
+        this.version = version;
+        this.privateKeyAlgorithm = privateKeyAlgorithm;
+        this.privateKey = privateKey;
+        this.attributes = attributes;
+    }
+
+    private PrivateKeyInfo(int version,
+            AlgorithmIdentifier privateKeyAlgorithm, byte[] privateKey,
+            List attributes, byte[] encoding) {
+        this(version, privateKeyAlgorithm, privateKey, attributes);
+        this.encoding = encoding;
+    }
+
+    /**
+     * @return Returns version.
+     */
+    public int getVersion() {
+        return version;
+    }
+
+    /**
+     * @return Returns AlgorithmIdentifier.
+     */
+    public AlgorithmIdentifier getAlgorithmIdentifier() {
+        return privateKeyAlgorithm;
+    }
+
+    /**
+     * @return Returns List of attributes.
+     */
+    public List getAttributes() {
+        return attributes;
+    }
+
+    /**
+     * @return Returns the OCTET STRING.
+     */
+    public byte[] getPrivateKey() {
+        return privateKey;
+    }
+
+    /**
+     * Returns ASN.1 encoded form of this PrivateKeyInfo.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
+
+    ASN1Integer.getInstance(), // version
+            AlgorithmIdentifier.ASN1, // AlgorithmIdentifier
+            ASN1OctetString.getInstance(), // privateKey
+
+            new ASN1Implicit(0, new ASN1SetOf(AttributeTypeAndValue.ASN1)) // attributes
+            }) {
+
+        {
+            setOptional(3); // attributes are OPTIONAL
+        }
+
+        protected Object getDecodedObject(BerInputStream in) {
+
+            Object[] values = (Object[]) in.content;
+
+            return new PrivateKeyInfo(ASN1Integer.toIntValue(values[0]),
+                    (AlgorithmIdentifier) values[1], (byte[]) values[2],
+                    (List) values[3], in.getEncoded());
+        }
+
+        protected void getValues(Object object, Object[] values) {
+
+            PrivateKeyInfo privateKeyInfo = (PrivateKeyInfo) object;
+
+            values[0] = ASN1Integer.fromIntValue(privateKeyInfo.version);
+            values[1] = privateKeyInfo.privateKeyAlgorithm;
+            values[2] = privateKeyInfo.privateKey;
+            values[3] = privateKeyInfo.attributes;
+        }
+    };
+
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/provider/cert/Cache.java b/libcore/security/src/main/java/org/apache/harmony/security/provider/cert/Cache.java
new file mode 100644
index 0000000..b76ad63
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/provider/cert/Cache.java
@@ -0,0 +1,339 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.provider.cert;
+
+import java.util.Arrays;
+
+/**
+ * The caching mechanism designed to speed up the process
+ * of Certificates/CRLs generation in the case of their repeated
+ * generation.
+ *
+ * It keeps correspondences between Objects (Certificates or CLRs)
+ * and arrays of bytes on the base of which the Objects have been generated,
+ * and provides the means to determine whether it contains the object built on
+ * the base of particular encoded form or not. If there are such
+ * objects they are returned from the cache, if not - newly generated
+ * objects can be saved in the cache.<br>
+ *
+ * The process of Certificate/CRL generation
+ * (implemented in <code>X509CertFactoryImpl</code>) is accompanied with
+ * prereading of the beginning of encoded form. This prefix is used to determine
+ * whether provided form is PEM encoding or not.<br>
+ *
+ * So the use of the prefix is the first point to (approximately)
+ * determine whether object to be generated is in the cache or not.
+ *
+ * The failure of the predetermination process tells us that there were not
+ * object generated from the encoded form with such prefix and we should
+ * generate (decode) the object. If predetermination is successful,
+ * we conduct the accurate search on the base of whole encoded form. <br>
+ *
+ * So to speed up the object generation process this caching mechanism provides
+ * the following functionality:<br>
+ *
+ *      1. With having of the beginning of the encoded form (prefix)
+ * it is possible to predetermine whether object has already been
+ * generated on the base of the encoding with the SIMILAR prefix or not.
+ * This process is not computationally expensive and takes a little time.
+ * But it prevents us from use of expensive full encoding
+ * search in the case of its failure.<br>
+ *
+ *      2. If predetermination ends with success, the whole encoding
+ * form should be provided to make the final answer: whether object has
+ * already been generated on the base of this PARTICULAR encoded form or not.
+ * If it is so - the cached object is returned from the cache,
+ * if not - new object should be generated and saved in the cache.<br>
+ *
+ * Note: The length of the prefixes of the encoded forms should not be
+ * less than correspondence (default value is 28).
+ */
+public class Cache {
+
+    // Hash code consist of 6 bytes: AABB00
+    // where:
+    // AA - 2 bytes for prefix hash
+    //      value generated on the base of the prefix of encoding
+    // BB - 2 bytes for tail hash
+    //      value generated on the base of the tail of encoding
+    // 00 - 2 reserved bytes equals to 0
+    //
+    // Note, that it is possible for 2 different arrays to have
+    // the similar hash codes.
+
+    // The masks to work with hash codes:
+    // the hash code without the reserved bytes
+    private static final long HASH_MASK = 0xFFFFFFFFFFFF0000L;
+    // the hash code of the prefix
+    private static final long PREFIX_HASH_MASK = 0xFFFFFFFF00000000L;
+    // the index value contained in reserved bytes
+    private static final int  INDEX_MASK = 0x00FFFF;
+
+    // size of the cache
+    private final int cache_size;
+    // the number of bytes which will be used for array hash generation.
+    private final int prefix_size;
+
+    // The following 3 arrays contain the information about cached objects.
+    // This information includes: hash of the array, encoded form of the object,
+    // and the object itself.
+    // The hash-encoding-object correspondence is made by means of index
+    // in the particular array. I.e. for index N hash contained in hashes[N]
+    // corresponds to the encoding contained in encodings[N] which corresponds
+    // to the object cached at cache[N]
+
+    // array containing the hash codes of encodings
+    private final long[] hashes;
+    // array containing the encodings of the cached objects
+    private final byte[][] encodings;
+    // array containing the cached objects
+    private final Object[] cache;
+
+    // This array is used to speed up the process of the search in the cache.
+    // This is an ordered array of the hash codes from 'hashes' array (described
+    // above) with last 2 (reserved) bytes equals to the index of
+    // the hash in the 'hashes' array. I.e. hash code ABCD00 with index 10 in
+    // the hashes array will be represented in this array as ABCD0A (10==0x0A)
+    // So this array contains ordered <hash to index> correspondences.
+    // Note, that every item in this array is unique.
+    private final long[] hashes_idx;
+
+    // the index of the last cached object
+    private int last_cached = 0;
+    // cache population indicator
+    private boolean cache_is_full = false;
+
+    /**
+     * Creates the Cache object.
+     * @param pref_size specifies how many leading/trailing bytes of object's
+     * encoded form will be used for hash computation
+     * @param size capacity of the cache to be created.
+     */
+    public Cache(int pref_size, int size) {
+        cache_size = size;
+        prefix_size = pref_size;
+        hashes = new long[cache_size];
+        hashes_idx = new long[cache_size];
+        encodings = new byte[cache_size][];
+        cache = new Object[cache_size];
+    }
+
+// BEGIN android-removed
+//    /**
+//     * Creates the Cache object of size of 900.
+//     * @param pref_size specifies how many leading/trailing bytes of object's
+//     * encoded form will be used for hash computation
+//     */
+//    public Cache(int pref_size) {
+//        this(pref_size, 900);
+//    }
+//
+//    /**
+//     * Creates the Cache object of size of 900.
+//     */
+//    public Cache() {
+//        this(28, 900);
+//    }
+// END android-removed
+
+// BEGIN android-added
+   /**
+     * Creates the Cache object of size of 9.
+     * @param pref_size specifies how many leading/trailing bytes of object's
+     * encoded form will be used for hash computation
+     */
+    public Cache(int pref_size) {
+        this(pref_size, 9);
+    }
+
+    /**
+     * Creates the Cache object of size of 9.
+     */
+    public Cache() {
+        this(28, 9);
+    }
+// END android-added
+    
+    /**
+     * Returns the hash code for the array. This code is used to
+     * predetermine whether the object was built on the base of the
+     * similar encoding or not (by means of <code>contains(long)</code> method),
+     * to exactly determine whether object is contained in the cache or not,
+     * and to put the object in the cache.
+     * Note: parameter array should be of length not less than
+     * specified by <code>prefix_size</code> (default 28)
+     * @param arr the byte array containing at least prefix_size leading bytes
+     * of the encoding.
+     * @return hash code for specified encoding prefix
+     */
+    public long getHash(byte[] arr) {
+        long hash = 0;
+        for (int i=1; i<prefix_size; i++) {
+            hash += (arr[i] & 0xFF);
+        } // it takes about 2 bytes for prefix_size == 28
+
+        // shift to the correct place
+        hash = hash << 32;
+        return hash;
+    }
+
+    /**
+     * Checks if there are any object in the cache generated
+     * on the base of encoding with prefix corresponding
+     * to the specified hash code.
+     * @param prefix_hash the hash code for the prefix
+     * of the encoding (retrieved by method <code>getHash(byte[]))</code>
+     * @return false if there were not any object generated
+     * on the base of encoding with specified hash code, true
+     * otherwise.
+     */
+    public boolean contains(long prefix_hash) {
+        int idx = -1*Arrays.binarySearch(hashes_idx, prefix_hash)-1;
+        if (idx == cache_size) {
+            return false;
+        } else {
+            return (hashes_idx[idx] & PREFIX_HASH_MASK) == prefix_hash;
+        }
+    }
+
+    /**
+     * Returns the object built on the base on the specified encoded
+     * form if it is contained in the cache and null otherwise.
+     * This method is computationally expensive and should be called only if
+     * the method <code>contains(long)</code> for the hash code returned true.
+     * @param hash the hash code for the prefix of the encoding
+     * (retrieved by method <code>getHash(byte[])</code>)
+     * @param encoding encoded form of the required object.
+     * @return the object corresponding to specified encoding or null if
+     * there is no such correspondence.
+     */
+    public Object get(long hash, byte[] encoding) {
+        hash |= getSuffHash(encoding);
+        int idx = -1*Arrays.binarySearch(hashes_idx, hash)-1;
+        if (idx == cache_size) {
+            return null;
+        }
+        while ((hashes_idx[idx] & HASH_MASK) == hash) {
+            int i = (int) (hashes_idx[idx] & INDEX_MASK) - 1;
+            if (Arrays.equals(encoding, encodings[i])) {
+                return cache[i];
+            }
+            idx++;
+            if (idx == cache_size) {
+                return null;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Puts the object into the cache.
+     * @param hash hash code for the prefix of the encoding
+     * @param encoding the encoded form of the object
+     * @param object the object to be saved in the cache
+     */
+    public void put(long hash, byte[] encoding, Object object) {
+        // check for empty space in the cache
+        if (last_cached == cache_size) {
+            // so cache is full, will erase the first entry in the
+            // cache (oldest entry). it could be better to throw out
+            // rarely used value instead of oldest one..
+            last_cached = 0;
+            cache_is_full = true;
+        }
+        // index pointing to the item of the table to be overwritten
+        int index = last_cached++;
+
+        // improve the hash value with info from the tail of encoding
+        hash |= getSuffHash(encoding);
+
+        if (cache_is_full) {
+            // indexing hash value to be overwritten:
+            long idx_hash = (hashes[index] | (index+1));
+            int idx = Arrays.binarySearch(hashes_idx, idx_hash);
+            if (idx < 0) {
+                // it will never happen because we use saved hash value
+                // (hashes[index])
+                System.out.println("WARNING! "+idx); //$NON-NLS-1$
+                idx = -(idx + 1);
+            }
+            long new_hash_idx = (hash | (index + 1));
+            int new_idx = Arrays.binarySearch(hashes_idx, new_hash_idx);
+            if (new_idx >= 0) {
+                // it's possible when we write the same hash in the same cell
+                if (idx != new_idx) {
+                    // it will never happen because we use the same
+                    // hash and the same index in hash table
+                    System.out.println("WARNING: "); //$NON-NLS-1$
+                    System.out.println(">> idx: "+idx+" new_idx: "+new_idx); //$NON-NLS-1$ //$NON-NLS-2$
+                }
+            } else {
+                new_idx = -(new_idx + 1);
+                // replace in sorted array
+                if (new_idx > idx) {
+                    System.arraycopy(hashes_idx, idx+1, hashes_idx, idx,
+                            new_idx - idx - 1);
+                    hashes_idx[new_idx-1] = new_hash_idx;
+                } else if (idx > new_idx) {
+                    System.arraycopy(hashes_idx, new_idx, hashes_idx, new_idx+1,
+                            idx - new_idx);
+                    hashes_idx[new_idx] = new_hash_idx;
+                } else { // idx == new_idx
+                    hashes_idx[new_idx] = new_hash_idx;
+                }
+            }
+        } else {
+            long idx_hash = (hash | (index + 1));
+            int idx = Arrays.binarySearch(hashes_idx, idx_hash);
+            if (idx < 0) {
+                // it will always be true because idx_hash depends on index
+                idx = -(idx + 1);
+            }
+            idx = idx - 1;
+            if (idx != cache_size - index - 1) {
+                // if not in the cell containing 0 (free cell), do copy:
+                System.arraycopy(hashes_idx, cache_size - index,
+                        hashes_idx, cache_size - index - 1,
+                        idx - (cache_size - index) + 1);
+            }
+            hashes_idx[idx] = idx_hash;
+        }
+        // overwrite the values in the tables:
+        hashes[index] = hash;
+        encodings[index] = encoding;
+        cache[index] = object;
+    }
+
+    // Returns the hash code built on the base of the tail of the encoded form
+    // @param arr - the array containing at least prefix_size trailing bytes
+    // of encoded form
+    private long getSuffHash(byte[] arr) {
+        long hash_addon = 0;
+        for (int i=arr.length-1; i>arr.length - prefix_size; i--) {
+            hash_addon += (arr[i] & 0xFF);
+        }
+        return hash_addon << 16;
+    }
+
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/provider/cert/DRLCertFactory.java b/libcore/security/src/main/java/org/apache/harmony/security/provider/cert/DRLCertFactory.java
new file mode 100644
index 0000000..2d75a5a
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/provider/cert/DRLCertFactory.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.provider.cert;
+
+import java.security.AccessController;
+import java.security.Provider;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ * Master class (provider) for X509 Certificate Factory
+ * Implementation.
+ */
+public final class DRLCertFactory extends Provider {
+
+    /**
+     * @serial
+     */
+    private static final long serialVersionUID = -7269650779605195879L;
+
+    /**
+     * Constructs the instance of the certificate factory provider.
+     */
+    public DRLCertFactory() {
+        // specification of the provider name, version, and description.
+        // security.151=Certificate Factory supports CRLs and Certificates in (PEM) ASN.1 DER encoded form, and Certification Paths in PkiPath and PKCS7 formats.
+
+        // BEGIN android-changed
+        // Avoid using a message resource string here, since it forces loading
+        // all the messages in a non-error context.
+        super("DRLCertFactory", 1.0, "ASN.1, DER, PkiPath, PKCS7"); //$NON-NLS-1$ //$NON-NLS-2$
+        // END android-changed
+                
+        AccessController.doPrivileged(new java.security.PrivilegedAction<Void>() {
+            public Void run() {
+                // register the service
+                put("CertificateFactory.X509", //$NON-NLS-1$
+                    "org.apache.harmony.security.provider.cert.X509CertFactoryImpl"); //$NON-NLS-1$
+                // mapping the alias
+                put("Alg.Alias.CertificateFactory.X.509", "X509"); //$NON-NLS-1$ //$NON-NLS-2$
+                    return null;
+            }
+        });
+    }
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/provider/cert/X509CRLEntryImpl.java b/libcore/security/src/main/java/org/apache/harmony/security/provider/cert/X509CRLEntryImpl.java
new file mode 100644
index 0000000..5902489
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/provider/cert/X509CRLEntryImpl.java
@@ -0,0 +1,181 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.provider.cert;
+
+import java.math.BigInteger;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRLEntry;
+import java.util.Date;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.x509.Extension;
+import org.apache.harmony.security.x509.Extensions;
+import org.apache.harmony.security.x509.TBSCertList;
+
+/**
+ * Implementation of X509CRLEntry. It wraps the instance
+ * of org.apache.harmony.security.x509.TBSCertList.RevokedCertificate
+ * obtained during the decoding of TBSCertList substructure
+ * of the CertificateList structure which is an X.509 form of CRL.
+ * (see RFC 3280 at http://www.ietf.org/rfc/rfc3280.txt)
+ * Normally the instances of this class are constructed by involving
+ * X509CRLImpl object.
+ * @see org.apache.harmony.security.x509.TBSCertList
+ * @see org.apache.harmony.security.provider.cert.X509CRLImpl
+ * @see java.security.cert.X509CRLEntry
+ */
+public class X509CRLEntryImpl extends X509CRLEntry {
+
+    // the crl entry object to be wrapped in X509CRLEntry
+    private final TBSCertList.RevokedCertificate rcert;
+    // the extensions of the entry
+    private final Extensions extensions;
+    // issuer of the revoked certificate described by this crl entry
+    private final X500Principal issuer;
+
+    // encoded form of this revoked certificate entry
+    private byte[] encoding;
+
+    /**
+     * Creates an instance on the base of existing
+     * <code>TBSCertList.RevokedCertificate</code> object and
+     * information about the issuer of revoked certificate.
+     * If specified issuer is null, it is supposed that issuer
+     * of the revoked certificate is the same as for involving CRL.
+     */
+    public X509CRLEntryImpl(TBSCertList.RevokedCertificate rcert,
+            X500Principal issuer) {
+        this.rcert = rcert;
+        this.extensions = rcert.getCrlEntryExtensions();
+        this.issuer = issuer;
+    }
+
+    // ---------------------------------------------------------------------
+    // ------ java.security.cert.X509CRLEntry method implementations -------
+    // ---------------------------------------------------------------------
+
+    /**
+     * @see java.security.cert.X509CRLEntry#getEncoded()
+     * method documentation for more info
+     */
+    public byte[] getEncoded() throws CRLException {
+        if (encoding == null) {
+            encoding = rcert.getEncoded();
+        }
+        byte[] result = new byte[encoding.length];
+        System.arraycopy(encoding, 0, result, 0, encoding.length);
+        return result;
+    }
+
+    /**
+     * @see java.security.cert.X509CRLEntry#getSerialNumber()
+     * method documentation for more info
+     */
+    public BigInteger getSerialNumber() {
+        return rcert.getUserCertificate();
+    }
+
+    /**
+     * @see java.security.cert.X509CRLEntry#getCertificateIssuer()
+     * method documentation for more info
+     */
+    public X500Principal getCertificateIssuer() {
+        return issuer;
+    }
+
+    /**
+     * @see java.security.cert.X509CRLEntry#getRevocationDate()
+     * method documentation for more info
+     */
+    public Date getRevocationDate() {
+        return rcert.getRevocationDate();
+    }
+
+    /**
+     * @see java.security.cert.X509CRLEntry#hasExtensions()
+     * method documentation for more info
+     */
+    public boolean hasExtensions() {
+        return (extensions != null) && (extensions.size() != 0);
+    }
+
+    /**
+     * @see java.security.cert.X509CRLEntry#toString()
+     * method documentation for more info
+     */
+    public String toString() {
+        return "X509CRLEntryImpl: "+rcert.toString(); //$NON-NLS-1$
+    }
+
+    // ---------------------------------------------------------------------
+    // ------ java.security.cert.X509Extension method implementations ------
+    // ---------------------------------------------------------------------
+
+    /**
+     * @see java.security.cert.X509Extension#getNonCriticalExtensionOIDs()
+     * method documentation for more info
+     */
+    public Set getNonCriticalExtensionOIDs() {
+        if (extensions == null) {
+            return null;
+        }
+        return extensions.getNonCriticalExtensions();
+    }
+
+    /**
+     * @see java.security.cert.X509Extension#getCriticalExtensionOIDs()
+     * method documentation for more info
+     */
+    public Set getCriticalExtensionOIDs() {
+        if (extensions == null) {
+            return null;
+        }
+        return extensions.getCriticalExtensions();
+    }
+
+    /**
+     * @see java.security.cert.X509Extension#getExtensionValue(String)
+     * method documentation for more info
+     */
+    public byte[] getExtensionValue(String oid) {
+        if (extensions == null) {
+            return null;
+        }
+        Extension ext = extensions.getExtensionByOID(oid);
+        return (ext == null) ? null : ext.getRawExtnValue();
+    }
+
+    /**
+     * @see java.security.cert.X509Extension#hasUnsupportedCriticalExtension()
+     * method documentation for more info
+     */
+    public boolean hasUnsupportedCriticalExtension() {
+        if (extensions == null) {
+            return false;
+        }
+        return extensions.hasUnsupportedCritical();
+    }
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/provider/cert/X509CRLImpl.java b/libcore/security/src/main/java/org/apache/harmony/security/provider/cert/X509CRLImpl.java
new file mode 100644
index 0000000..d53eb8a
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/provider/cert/X509CRLImpl.java
@@ -0,0 +1,508 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.provider.cert;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.internal.nls.Messages;
+import org.apache.harmony.security.utils.AlgNameMapper;
+import org.apache.harmony.security.x509.CertificateList;
+import org.apache.harmony.security.x509.Extension;
+import org.apache.harmony.security.x509.Extensions;
+import org.apache.harmony.security.x509.TBSCertList;
+
+/**
+ * This class is an implementation of X509CRL. It wraps
+ * the instance of org.apache.harmony.security.x509.CertificateList
+ * built on the base of provided ASN.1 DER encoded form of
+ * CertificateList structure (as specified in RFC 3280
+ * http://www.ietf.org/rfc/rfc3280.txt).
+ * Implementation supports work with indirect CRLs.
+ * @see org.apache.harmony.security.x509.CertificateList
+ * @see java.security.cert.X509CRL
+ */
+public class X509CRLImpl extends X509CRL {
+
+    // the core object to be wrapped in X509CRL
+    private final CertificateList crl;
+
+    // To speed up access to the info, the following fields
+    // cache values retrieved from the CertificateList object
+    private final TBSCertList tbsCertList;
+    private byte[] tbsCertListEncoding;
+    private final Extensions extensions;
+    private X500Principal issuer;
+    private ArrayList entries;
+    private int entriesSize;
+    private byte[] signature;
+    private String sigAlgOID;
+    private String sigAlgName;
+    private byte[] sigAlgParams;
+
+    // encoded form of crl
+    private byte[] encoding;
+
+    // indicates whether the signature algorithm parameters are null
+    private boolean nullSigAlgParams;
+    // indicates whether the crl entries have already been retrieved
+    // from CertificateList object (crl)
+    private boolean entriesRetrieved;
+
+    // indicates whether this X.509 CRL is direct or indirect
+    // (see rfc 3280 http://www.ietf.org/rfc/rfc3280.txt, p 5.)
+    private boolean isIndirectCRL;
+    // if crl is indirect, this field holds an info about how
+    // many of the leading certificates in the list are issued
+    // by the same issuer as CRL.
+    private int nonIndirectEntriesSize;
+
+    /**
+     * Creates X.509 CRL by wrapping of the specified CertificateList object.
+     */
+    public X509CRLImpl(CertificateList crl) {
+        this.crl = crl;
+        this.tbsCertList = crl.getTbsCertList();
+        this.extensions = tbsCertList.getCrlExtensions();
+    }
+
+    /**
+     * Creates X.509 CRL on the base of ASN.1 DER encoded form of
+     * the CRL (CertificateList structure described in RFC 3280)
+     * provided via input stream.
+     * @throws CRLException if decoding errors occur.
+     */
+    public X509CRLImpl(InputStream in) throws CRLException {
+        try {
+            // decode CertificateList structure
+            this.crl = (CertificateList) CertificateList.ASN1.decode(in);
+            this.tbsCertList = crl.getTbsCertList();
+            this.extensions = tbsCertList.getCrlExtensions();
+        } catch (IOException e) {
+            throw new CRLException(e);
+        }
+    }
+
+    /**
+     * Creates X.509 CRL on the base of ASN.1 DER encoded form of
+     * the CRL (CertificateList structure described in RFC 3280)
+     * provided via array of bytes.
+     * @throws IOException if decoding errors occur.
+     */
+    public X509CRLImpl(byte[] encoding) throws IOException {
+        this((CertificateList) CertificateList.ASN1.decode(encoding));
+    }
+
+    // ---------------------------------------------------------------------
+    // ----- java.security.cert.X509CRL abstract method implementations ----
+    // ---------------------------------------------------------------------
+
+    /**
+     * @see java.security.cert.X509CRL#getEncoded()
+     * method documentation for more info
+     */
+    public byte[] getEncoded() throws CRLException {
+        if (encoding == null) {
+            encoding = crl.getEncoded();
+        }
+        byte[] result = new byte[encoding.length];
+        System.arraycopy(encoding, 0, result, 0, encoding.length);
+        return result;
+    }
+
+    /**
+     * @see java.security.cert.X509CRL#getVersion()
+     * method documentation for more info
+     */
+    public int getVersion() {
+        return tbsCertList.getVersion();
+    }
+
+    /**
+     * @see java.security.cert.X509CRL#getIssuerDN()
+     * method documentation for more info
+     */
+    public Principal getIssuerDN() {
+        if (issuer == null) {
+            issuer = tbsCertList.getIssuer().getX500Principal();
+        }
+        return issuer;
+    }
+
+    /**
+     * @see java.security.cert.X509CRL#getIssuerX500Principal()
+     * method documentation for more info
+     */
+    public X500Principal getIssuerX500Principal() {
+        if (issuer == null) {
+            issuer = tbsCertList.getIssuer().getX500Principal();
+        }
+        return issuer;
+    }
+
+    /**
+     * @see java.security.cert.X509CRL#getThisUpdate()
+     * method documentation for more info
+     */
+    public Date getThisUpdate() {
+        return tbsCertList.getThisUpdate();
+    }
+
+    /**
+     * @see java.security.cert.X509CRL#getNextUpdate()
+     * method documentation for more info
+     */
+    public Date getNextUpdate() {
+        return tbsCertList.getNextUpdate();
+    }
+
+    /*
+     * Retrieves the crl entries (TBSCertList.RevokedCertificate objects)
+     * from the TBSCertList structure and converts them to the
+     * X509CRLEntryImpl objects
+     */
+    private void retirieveEntries() {
+        entriesRetrieved = true;
+        List rcerts = tbsCertList.getRevokedCertificates();
+        if (rcerts == null) {
+            return;
+        }
+        entriesSize = rcerts.size();
+        entries = new ArrayList(entriesSize);
+        // null means that revoked certificate issuer is the same as CRL issuer
+        X500Principal rcertIssuer = null;
+        for (int i=0; i<entriesSize; i++) {
+            TBSCertList.RevokedCertificate rcert =
+                (TBSCertList.RevokedCertificate) rcerts.get(i);
+            X500Principal iss = rcert.getIssuer();
+            if (iss != null) {
+                // certificate issuer differs from CRL issuer
+                // and CRL is indirect.
+                rcertIssuer = iss;
+                isIndirectCRL = true;
+                // remember how many leading revoked certificates in the
+                // list are issued by the same issuer as issuer of CRL
+                // (these certificates are first in the list)
+                nonIndirectEntriesSize = i;
+            }
+            entries.add(new X509CRLEntryImpl(rcert, rcertIssuer));
+        }
+    }
+
+    /**
+     * Searches for certificate in CRL.
+     * This method supports indirect CRLs: if CRL is indirect method takes
+     * into account serial number and issuer of the certificate,
+     * if CRL issued by CA (i.e. it is not indirect) search is done only
+     * by serial number of the specified certificate.
+     * @see java.security.cert.X509CRL#getRevokedCertificate(X509Certificate)
+     * method documentation for more info
+     */
+    public X509CRLEntry getRevokedCertificate(X509Certificate certificate) {
+        if (certificate == null) {
+            throw new NullPointerException();
+        }
+        if (!entriesRetrieved) {
+            retirieveEntries();
+        }
+        if (entries == null) {
+            return null;
+        }
+        BigInteger serialN = certificate.getSerialNumber();
+        if (isIndirectCRL) {
+            // search in indirect crl
+            X500Principal certIssuer = certificate.getIssuerX500Principal();
+            if (certIssuer.equals(getIssuerX500Principal())) {
+                // certificate issuer is CRL issuer
+                certIssuer = null;
+            }
+            for (int i=0; i<entriesSize; i++) {
+                X509CRLEntry entry = (X509CRLEntry) entries.get(i);
+                // check the serial number of revoked certificate
+                if (serialN.equals(entry.getSerialNumber())) {
+                    // revoked certificate issuer
+                    X500Principal iss = entry.getCertificateIssuer();
+                    // check the issuer of revoked certificate
+                    if (certIssuer != null) {
+                        // certificate issuer is not a CRL issuer, so
+                        // check issuers for equality
+                        if (certIssuer.equals(iss)) {
+                            return entry;
+                        }
+                    } else if (iss == null) {
+                        // both certificates was issued by CRL issuer
+                        return entry;
+                    }
+                }
+            }
+        } else {
+            // search in CA's (non indirect) crl: just look up the serial number
+            for (int i=0; i<entriesSize; i++) {
+                X509CRLEntry entry = (X509CRLEntry) entries.get(i);
+                if (serialN.equals(entry.getSerialNumber())) {
+                    return entry;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Method searches for CRL entry with specified serial number.
+     * The method will search only certificate issued by CRL's issuer.
+     * @see java.security.cert.X509CRL#getRevokedCertificate(BigInteger)
+     * method documentation for more info
+     */
+    public X509CRLEntry getRevokedCertificate(BigInteger serialNumber) {
+        if (!entriesRetrieved) {
+            retirieveEntries();
+        }
+        if (entries == null) {
+            return null;
+        }
+        for (int i=0; i<nonIndirectEntriesSize; i++) {
+            X509CRLEntry entry = (X509CRLEntry) entries.get(i);
+            if (serialNumber.equals(entry.getSerialNumber())) {
+                return entry;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @see java.security.cert.X509CRL#getRevokedCertificates()
+     * method documentation for more info
+     */
+    public Set<? extends X509CRLEntry> getRevokedCertificates() {
+        if (!entriesRetrieved) {
+            retirieveEntries();
+        }
+        if (entries == null) {
+            return null;
+        }
+        return new HashSet(entries);
+    }
+
+    /**
+     * @see java.security.cert.X509CRL#getTBSCertList()
+     * method documentation for more info
+     */
+    public byte[] getTBSCertList() throws CRLException {
+        if (tbsCertListEncoding == null) {
+            tbsCertListEncoding = tbsCertList.getEncoded();
+        }
+        byte[] result = new byte[tbsCertListEncoding.length];
+        System.arraycopy(tbsCertListEncoding, 0,
+                result, 0, tbsCertListEncoding.length);
+        return result;
+    }
+
+    /**
+     * @see java.security.cert.X509CRL#getSignature()
+     * method documentation for more info
+     */
+    public byte[] getSignature() {
+        if (signature == null) {
+            signature = crl.getSignatureValue();
+        }
+        byte[] result = new byte[signature.length];
+        System.arraycopy(signature, 0, result, 0, signature.length);
+        return result;
+    }
+
+    /**
+     * @see java.security.cert.X509CRL#getSigAlgName()
+     * method documentation for more info
+     */
+    public String getSigAlgName() {
+        if (sigAlgOID == null) {
+            sigAlgOID = tbsCertList.getSignature().getAlgorithm();
+            sigAlgName = AlgNameMapper.map2AlgName(sigAlgOID);
+            if (sigAlgName == null) {
+                sigAlgName = sigAlgOID;
+            }
+        }
+        return sigAlgName;
+    }
+
+    /**
+     * @see java.security.cert.X509CRL#getSigAlgOID()
+     * method documentation for more info
+     */
+    public String getSigAlgOID() {
+        if (sigAlgOID == null) {
+            sigAlgOID = tbsCertList.getSignature().getAlgorithm();
+            sigAlgName = AlgNameMapper.map2AlgName(sigAlgOID);
+            if (sigAlgName == null) {
+                sigAlgName = sigAlgOID;
+            }
+        }
+        return sigAlgOID;
+    }
+
+    /**
+     * @see java.security.cert.X509CRL#getSigAlgParams()
+     * method documentation for more info
+     */
+    public byte[] getSigAlgParams() {
+        if (nullSigAlgParams) {
+            return null;
+        }
+        if (sigAlgParams == null) {
+            sigAlgParams = tbsCertList.getSignature().getParameters();
+            if (sigAlgParams == null) {
+                nullSigAlgParams = true;
+                return null;
+            }
+        }
+        return sigAlgParams;
+    }
+
+    /**
+     * @see java.security.cert.X509CRL#verify(PublicKey key)
+     * method documentation for more info
+     */
+    public void verify(PublicKey key)
+                     throws CRLException, NoSuchAlgorithmException,
+                            InvalidKeyException, NoSuchProviderException,
+                            SignatureException {
+        Signature signature = Signature.getInstance(getSigAlgName());
+        signature.initVerify(key);
+        byte[] tbsEncoding = tbsCertList.getEncoded();
+        signature.update(tbsEncoding, 0, tbsEncoding.length);
+        if (!signature.verify(crl.getSignatureValue())) {
+            throw new SignatureException(Messages.getString("security.15C")); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * @see java.security.cert.X509CRL#verify(PublicKey key, String sigProvider)
+     * method documentation for more info
+     */
+    public void verify(PublicKey key, String sigProvider)
+                     throws CRLException, NoSuchAlgorithmException,
+                            InvalidKeyException, NoSuchProviderException,
+                            SignatureException {
+        Signature signature = Signature.getInstance(
+                                            getSigAlgName(), sigProvider);
+        signature.initVerify(key);
+        byte[] tbsEncoding = tbsCertList.getEncoded();
+        signature.update(tbsEncoding, 0, tbsEncoding.length);
+        if (!signature.verify(crl.getSignatureValue())) {
+            throw new SignatureException(Messages.getString("security.15C")); //$NON-NLS-1$
+        }
+    }
+
+    // ---------------------------------------------------------------------
+    // ------ java.security.cert.CRL abstract method implementations -------
+    // ---------------------------------------------------------------------
+
+    /**
+     * @see java.security.cert.CRL#isRevoked(Certificate)
+     * method documentation for more info
+     */
+    public boolean isRevoked(Certificate cert) {
+        if (!(cert instanceof X509Certificate)) {
+            return false;
+        }
+        return getRevokedCertificate((X509Certificate) cert) != null;
+    }
+
+    /**
+     * @see java.security.cert.CRL#toString()
+     * method documentation for more info
+     */
+    public String toString() {
+        return crl.toString();
+    }
+
+    // ---------------------------------------------------------------------
+    // ------ java.security.cert.X509Extension method implementations ------
+    // ---------------------------------------------------------------------
+
+    /**
+     * @see java.security.cert.X509Extension#getNonCriticalExtensionOIDs()
+     * method documentation for more info
+     */
+    public Set getNonCriticalExtensionOIDs() {
+        if (extensions == null) {
+            return null;
+        }
+        return extensions.getNonCriticalExtensions();
+    }
+
+    /**
+     * @see java.security.cert.X509Extension#getCriticalExtensionOIDs()
+     * method documentation for more info
+     */
+    public Set getCriticalExtensionOIDs() {
+        if (extensions == null) {
+            return null;
+        }
+        return extensions.getCriticalExtensions();
+    }
+
+    /**
+     * @see java.security.cert.X509Extension#getExtensionValue(String)
+     * method documentation for more info
+     */
+    public byte[] getExtensionValue(String oid) {
+        if (extensions == null) {
+            return null;
+        }
+        Extension ext = extensions.getExtensionByOID(oid);
+        return (ext == null) ? null : ext.getRawExtnValue();
+    }
+
+    /**
+     * @see java.security.cert.X509Extension#hasUnsupportedCriticalExtension()
+     * method documentation for more info
+     */
+    public boolean hasUnsupportedCriticalExtension() {
+        if (extensions == null) {
+            return false;
+        }
+        return extensions.hasUnsupportedCritical();
+    }
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/provider/cert/X509CertFactoryImpl.java b/libcore/security/src/main/java/org/apache/harmony/security/provider/cert/X509CertFactoryImpl.java
new file mode 100644
index 0000000..17fd6f7
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/provider/cert/X509CertFactoryImpl.java
@@ -0,0 +1,935 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.provider.cert;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+import java.security.cert.CertPath;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactorySpi;
+import java.security.cert.X509CRL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.harmony.luni.util.Base64;
+import org.apache.harmony.security.asn1.ASN1Constants;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.internal.nls.Messages;
+import org.apache.harmony.security.pkcs7.ContentInfo;
+import org.apache.harmony.security.pkcs7.SignedData;
+import org.apache.harmony.security.x509.CertificateList;
+
+/**
+ * X509 Certificate Factory Service Provider Interface Implementation.
+ * It supports CRLs and Certificates in (PEM) ASN.1 DER encoded form,
+ * and Certification Paths in PkiPath and PKCS7 formats.
+ * For Certificates and CRLs factory maintains the caching
+ * mechanisms allowing to speed up repeated Certificate/CRL
+ * generation.
+ * @see Cache
+ */
+public class X509CertFactoryImpl extends CertificateFactorySpi {
+
+    // number of leading/trailing bytes used for cert hash computation
+    private static int CERT_CACHE_SEED_LENGTH = 28;
+    // certificate cache
+    private static Cache CERT_CACHE = new Cache(CERT_CACHE_SEED_LENGTH);
+    // number of leading/trailing bytes used for crl hash computation
+    private static int CRL_CACHE_SEED_LENGTH = 24;
+    // crl cache
+    private static Cache CRL_CACHE = new Cache(CRL_CACHE_SEED_LENGTH);
+
+    /**
+     * Default constructor.
+     * Creates the instance of Certificate Factory SPI ready for use.
+     */
+    public X509CertFactoryImpl() { }
+
+    /**
+     * Generates the X.509 certificate from the data in the stream.
+     * The data in the stream can be either in ASN.1 DER encoded X.509
+     * certificate, or PEM (Base64 encoding bounded by
+     * <code>"-----BEGIN CERTIFICATE-----"</code> at the beginning and
+     * <code>"-----END CERTIFICATE-----"</code> at the end) representation
+     * of the former encoded form.
+     *
+     * Before the generation the encoded form is looked up in
+     * the cache. If the cache contains the certificate with requested encoded
+     * form it is returned from it, otherwise it is generated by ASN.1
+     * decoder.
+     *
+     * @see java.security.cert.CertificateFactorySpi#engineGenerateCertificate(InputStream)
+     * method documentation for more info
+     */
+    public Certificate engineGenerateCertificate(InputStream inStream)
+            throws CertificateException {
+        if (inStream == null) {
+            throw new CertificateException(Messages.getString("security.153")); //$NON-NLS-1$
+        }
+        try {
+            if (!inStream.markSupported()) {
+                // create the mark supporting wrapper
+                inStream = new RestoringInputStream(inStream);
+            }
+            // mark is needed to recognize the format of the provided encoding
+            // (ASN.1 or PEM)
+            inStream.mark(1);
+            // check whether the provided certificate is in PEM encoded form
+            if (inStream.read() == '-') {
+                // decode PEM, retrieve CRL
+                return getCertificate(decodePEM(inStream, CERT_BOUND_SUFFIX));
+            } else {
+                inStream.reset();
+                // retrieve CRL
+                return getCertificate(inStream);
+            }
+        } catch (IOException e) {
+            throw new CertificateException(e);
+        }
+    }
+
+    /**
+     * Generates the collection of the certificates on the base of provided
+     * via input stream encodings.
+     * @see java.security.cert.CertificateFactorySpi#engineGenerateCertificates(InputStream)
+     * method documentation for more info
+     */
+    public Collection<? extends Certificate>
+            engineGenerateCertificates(InputStream inStream)
+                throws CertificateException {
+        if (inStream == null) {
+            throw new CertificateException(Messages.getString("security.153")); //$NON-NLS-1$
+        }
+        ArrayList result = new ArrayList();
+        try {
+            if (!inStream.markSupported()) {
+                // create the mark supporting wrapper
+                inStream = new RestoringInputStream(inStream);
+            }
+            // if it is PEM encoded form this array will contain the encoding
+            // so ((it is PEM) <-> (encoding != null))
+            byte[] encoding = null;
+            // The following by SEQUENCE ASN.1 tag, used for
+            // recognizing the data format 
+            // (is it PKCS7 ContentInfo structure, X.509 Certificate, or
+            // unsupported encoding)
+            int second_asn1_tag = -1;
+            inStream.mark(1);
+            int ch;
+            while ((ch = inStream.read()) != -1) {
+                // check if it is PEM encoded form
+                if (ch == '-') { // beginning of PEM encoding ('-' char)
+                    // decode PEM chunk and store its content (ASN.1 encoding)
+                    encoding = decodePEM(inStream, FREE_BOUND_SUFFIX);
+                } else if (ch == 0x30) { // beginning of ASN.1 sequence (0x30)
+                    encoding = null;
+                    inStream.reset();
+                    // prepare for data format determination
+                    inStream.mark(CERT_CACHE_SEED_LENGTH);
+                } else { // unsupported data
+                    if (result.size() == 0) {
+                        throw new CertificateException(
+                                Messages.getString("security.15F")); //$NON-NLS-1$
+                    } else {
+                        // it can be trailing user data,
+                        // so keep it in the stream
+                        inStream.reset();
+                        return result;
+                    }
+                }
+                // Check the data format
+                BerInputStream in = (encoding == null)
+                                        ? new BerInputStream(inStream)
+                                        : new BerInputStream(encoding);
+                // read the next ASN.1 tag
+                second_asn1_tag = in.next(); // inStream position changed
+                if (encoding == null) {
+                    // keep whole structure in the stream
+                    inStream.reset();
+                }
+                // check if it is a TBSCertificate structure
+                if (second_asn1_tag != ASN1Constants.TAG_C_SEQUENCE) {
+                    if (result.size() == 0) {
+                        // there were not read X.509 Certificates, so 
+                        // break the cycle and check 
+                        // whether it is PKCS7 structure
+                        break;
+                    } else {
+                        // it can be trailing user data,
+                        // so return what we already read
+                        return result;
+                    }
+                } else {
+                    if (encoding == null) {
+                        result.add(getCertificate(inStream));
+                    } else {
+                        result.add(getCertificate(encoding));
+                    }
+                }
+                // mark for the next iteration
+                inStream.mark(1);
+            }
+            if (result.size() != 0) {
+                // some Certificates have been read
+                return result;
+            } else if (ch == -1) {
+                throw new CertificateException(
+                        Messages.getString("security.155")); //$NON-NLS-1$
+            }
+            // else: check if it is PKCS7
+            if (second_asn1_tag == ASN1Constants.TAG_OID) {
+                // it is PKCS7 ContentInfo structure, so decode it
+                ContentInfo info = (ContentInfo) 
+                    ((encoding != null)
+                        ? ContentInfo.ASN1.decode(encoding)
+                        : ContentInfo.ASN1.decode(inStream));
+                // retrieve SignedData
+                SignedData data = info.getSignedData();
+                if (data == null) {
+                    throw new CertificateException(
+                            Messages.getString("security.154")); //$NON-NLS-1$
+                }
+                List certs = data.getCertificates();
+                if (certs != null) {
+                    for (int i = 0; i < certs.size(); i++) {
+                        result.add(new X509CertImpl(
+                            (org.apache.harmony.security.x509.Certificate)
+                                certs.get(i)));
+                    }
+                }
+                return result;
+            }
+            // else: Unknown data format
+            throw new CertificateException(
+                            Messages.getString("security.15F")); //$NON-NLS-1$
+        } catch (IOException e) {
+            throw new CertificateException(e);
+        }
+    }
+
+    /**
+     * @see java.security.cert.CertificateFactorySpi#engineGenerateCRL(InputStream)
+     * method documentation for more info
+     */
+    public CRL engineGenerateCRL(InputStream inStream)
+            throws CRLException {
+        if (inStream == null) {
+            throw new CRLException(Messages.getString("security.153")); //$NON-NLS-1$
+        }
+        try {
+            if (!inStream.markSupported()) {
+                // Create the mark supporting wrapper
+                // Mark is needed to recognize the format 
+                // of provided encoding form (ASN.1 or PEM)
+                inStream = new RestoringInputStream(inStream);
+            }
+            inStream.mark(1);
+            // check whether the provided crl is in PEM encoded form
+            if (inStream.read() == '-') {
+                // decode PEM, retrieve CRL
+                return getCRL(decodePEM(inStream, FREE_BOUND_SUFFIX));
+            } else {
+                inStream.reset();
+                // retrieve CRL
+                return getCRL(inStream);
+            }
+        } catch (IOException e) {
+            throw new CRLException(e);
+        }
+    }
+
+    /**
+     * @see java.security.cert.CertificateFactorySpi#engineGenerateCRLs(InputStream)
+     * method documentation for more info
+     */
+    public Collection<? extends CRL> engineGenerateCRLs(InputStream inStream)
+            throws CRLException {
+        if (inStream == null) {
+            throw new CRLException(Messages.getString("security.153")); //$NON-NLS-1$
+        }
+        ArrayList result = new ArrayList();
+        try {
+            if (!inStream.markSupported()) {
+                inStream = new RestoringInputStream(inStream);
+            }
+            // if it is PEM encoded form this array will contain the encoding
+            // so ((it is PEM) <-> (encoding != null))
+            byte[] encoding = null;
+            // The following by SEQUENCE ASN.1 tag, used for
+            // recognizing the data format 
+            // (is it PKCS7 ContentInfo structure, X.509 CRL, or
+            // unsupported encoding)
+            int second_asn1_tag = -1;
+            inStream.mark(1);
+            int ch;
+            while ((ch = inStream.read()) != -1) {
+                // check if it is PEM encoded form
+                if (ch == '-') { // beginning of PEM encoding ('-' char)
+                    // decode PEM chunk and store its content (ASN.1 encoding)
+                    encoding = decodePEM(inStream, FREE_BOUND_SUFFIX);
+                } else if (ch == 0x30) { // beginning of ASN.1 sequence (0x30)
+                    encoding = null;
+                    inStream.reset();
+                    // prepare for data format determination
+                    inStream.mark(CRL_CACHE_SEED_LENGTH);
+                } else { // unsupported data
+                    if (result.size() == 0) {
+                        throw new CRLException(
+                                Messages.getString("security.15F")); //$NON-NLS-1$
+                    } else {
+                        // it can be trailing user data,
+                        // so keep it in the stream
+                        inStream.reset();
+                        return result;
+                    }
+                }
+                // Check the data format
+                BerInputStream in = (encoding == null)
+                                        ? new BerInputStream(inStream)
+                                        : new BerInputStream(encoding);
+                // read the next ASN.1 tag
+                second_asn1_tag = in.next();
+                if (encoding == null) {
+                    // keep whole structure in the stream
+                    inStream.reset();
+                }
+                // check if it is a TBSCertList structure
+                if (second_asn1_tag != ASN1Constants.TAG_C_SEQUENCE) {
+                    if (result.size() == 0) {
+                        // there were not read X.509 CRLs, so 
+                        // break the cycle and check 
+                        // whether it is PKCS7 structure
+                        break;
+                    } else {
+                        // it can be trailing user data,
+                        // so return what we already read
+                        return result;
+                    }
+                } else {
+                    if (encoding == null) {
+                        result.add(getCRL(inStream));
+                    } else {
+                        result.add(getCRL(encoding));
+                    }
+                }
+                inStream.mark(1);
+            }
+            if (result.size() != 0) {
+                // the stream was read out
+                return result;
+            } else if (ch == -1) {
+                throw new CRLException(
+                        Messages.getString("security.155")); //$NON-NLS-1$
+            }
+            // else: check if it is PKCS7
+            if (second_asn1_tag == ASN1Constants.TAG_OID) {
+                // it is PKCS7 ContentInfo structure, so decode it
+                ContentInfo info = (ContentInfo) 
+                    ((encoding != null)
+                        ? ContentInfo.ASN1.decode(encoding)
+                        : ContentInfo.ASN1.decode(inStream));
+                // retrieve SignedData
+                SignedData data = info.getSignedData();
+                if (data == null) {
+                    throw new CRLException(
+                            Messages.getString("security.154")); //$NON-NLS-1$
+                }
+                List crls = data.getCRLs();
+                if (crls != null) {
+                    for (int i = 0; i < crls.size(); i++) {
+                        result.add(new X509CRLImpl(
+                            (CertificateList) crls.get(i)));
+                    }
+                }
+                return result;
+            }
+            // else: Unknown data format
+            throw new CRLException(
+                        Messages.getString("security.15F")); //$NON-NLS-1$
+        } catch (IOException e) {
+            throw new CRLException(e);
+        }
+    }
+
+    /**
+     * @see java.security.cert.CertificateFactorySpi#engineGenerateCertPath(InputStream)
+     * method documentation for more info
+     */
+    public CertPath engineGenerateCertPath(InputStream inStream)
+            throws CertificateException {
+        if (inStream == null) {
+            throw new CertificateException(
+                    Messages.getString("security.153")); //$NON-NLS-1$
+        }
+        return engineGenerateCertPath(inStream, "PkiPath"); //$NON-NLS-1$
+    }
+
+    /**
+     * @see java.security.cert.CertificateFactorySpi#engineGenerateCertPath(InputStream,String)
+     * method documentation for more info
+     */
+    public CertPath engineGenerateCertPath(
+            InputStream inStream, String encoding) throws CertificateException {
+        if (inStream == null) {
+            throw new CertificateException(
+                    Messages.getString("security.153")); //$NON-NLS-1$
+        }
+        if (!inStream.markSupported()) {
+            inStream = new RestoringInputStream(inStream);
+        }
+        try {
+            inStream.mark(1);
+            int ch;
+
+            // check if it is PEM encoded form
+            if ((ch = inStream.read()) == '-') {
+                // decode PEM chunk into ASN.1 form and decode CertPath object
+                return X509CertPathImpl.getInstance(
+                        decodePEM(inStream, FREE_BOUND_SUFFIX), encoding);
+            } else if (ch == 0x30) { // ASN.1 Sequence
+                inStream.reset();
+                // decode ASN.1 form
+                return X509CertPathImpl.getInstance(inStream, encoding);
+            } else {
+                throw new CertificateException(
+                            Messages.getString("security.15F")); //$NON-NLS-1$
+            }
+        } catch (IOException e) {
+            throw new CertificateException(e);
+        }
+    }
+
+    /**
+     * @see java.security.cert.CertificateFactorySpi#engineGenerateCertPath(List)
+     * method documentation for more info
+     */
+    public CertPath engineGenerateCertPath(List certificates)
+            throws CertificateException {
+        return new X509CertPathImpl(certificates);
+    }
+
+    /**
+     * @see java.security.cert.CertificateFactorySpi#engineGetCertPathEncodings()
+     * method documentation for more info
+     */
+    public Iterator<String> engineGetCertPathEncodings() {
+        return X509CertPathImpl.encodings.iterator();
+    }
+
+    // ---------------------------------------------------------------------
+    // ------------------------ Staff methods ------------------------------
+    // ---------------------------------------------------------------------
+
+    private static byte[] pemBegin = "-----BEGIN".getBytes(); //$NON-NLS-1$
+    private static byte[] pemClose = "-----END".getBytes(); //$NON-NLS-1$
+    /**
+     * Code describing free format for PEM boundary suffix:
+     * "^-----BEGIN.*\n"         at the beginning, and<br>
+     * "\n-----END.*(EOF|\n)$"   at the end.
+     */
+    private static byte[] FREE_BOUND_SUFFIX = null;
+    /**
+     * Code describing PEM boundary suffix for X.509 certificate:
+     * "^-----BEGIN CERTIFICATE-----\n"   at the beginning, and<br>
+     * "\n-----END CERTIFICATE-----"   at the end.
+     */
+    private static byte[] CERT_BOUND_SUFFIX = 
+        " CERTIFICATE-----".getBytes(); //$NON-NLS-1$
+
+    /**
+     * Method retrieves the PEM encoded data from the stream 
+     * and returns its decoded representation.
+     * Method checks correctness of PEM boundaries. It supposes that
+     * the first '-' of the opening boundary has already been read from
+     * the stream. So first of all it checks that the leading bytes
+     * are equal to "-----BEGIN" boundary prefix. Than if boundary_suffix
+     * is not null, it checks that next bytes equal to boundary_suffix
+     * + new line char[s] ([CR]LF).
+     * If boundary_suffix parameter is null, method supposes free suffix
+     * format and skips any bytes until the new line.<br>
+     * After the opening boundary has been read and checked, the method
+     * read Base64 encoded data until closing PEM boundary is not reached.<br>
+     * Than it checks closing boundary - it should start with new line +
+     * "-----END" + boundary_suffix. If boundary_suffix is null, 
+     * any characters are skipped until the new line.<br>
+     * After this any trailing new line characters are skipped from the stream,
+     * Base64 encoding is decoded and returned.
+     * @param inStream the stream containing the PEM encoding.
+     * @param boundary_suffix the suffix of expected PEM multipart 
+     * boundary delimiter.<br>
+     * If it is null, that any character sequences are accepted.
+     * @throws IOException If PEM boundary delimiter does not comply 
+     * with expected or some I/O or decoding problems occur.
+     */
+    private byte[] decodePEM(InputStream inStream, byte[] boundary_suffix) 
+                                                        throws IOException {
+        int ch; // the char to be read
+        // check and skip opening boundary delimiter 
+        // (first '-' is supposed as already read)
+        for (int i=1; i<pemBegin.length; i++) {
+            if (pemBegin[i] != (ch = inStream.read())) {
+                throw new IOException(
+                    "Incorrect PEM encoding: '-----BEGIN"
+                    + ((boundary_suffix == null) 
+                        ? "" : new String(boundary_suffix))
+                    + "' is expected as opening delimiter boundary.");
+            }
+        }
+        if (boundary_suffix == null) {
+            // read (skip) the trailing characters of 
+            // the beginning PEM boundary delimiter
+            while ((ch = inStream.read()) != '\n') {
+                if (ch == -1) {
+                    throw new IOException(
+                        Messages.getString("security.156")); //$NON-NLS-1$
+                }
+            }
+        } else {
+            for (int i=0; i<boundary_suffix.length; i++) {
+                if (boundary_suffix[i] != inStream.read()) {
+                    throw new IOException(
+                        Messages.getString("security.15B", //$NON-NLS-1$
+                            ((boundary_suffix == null) 
+                                ? "" 
+                                : new String(boundary_suffix)))); //$NON-NLS-1$
+                }
+            }
+            // read new line characters
+            if ((ch = inStream.read()) == '\r') {
+                // CR has been read, now read LF character
+                ch = inStream.read();
+            }
+            if (ch != '\n') {
+                throw new IOException(
+                    Messages.getString("security.15B2")); //$NON-NLS-1$
+            }
+        }
+        int size = 1024; // the size of the buffer containing Base64 data
+        byte[] buff = new byte[size];
+        int index = 0;
+        // read bytes while ending boundary delimiter is not reached
+        while ((ch = inStream.read()) != '-') {
+            if (ch == -1) {
+                throw new IOException(
+                        Messages.getString("security.157")); //$NON-NLS-1$
+            }
+            buff[index++] = (byte) ch;
+            if (index == size) {
+                // enlarge the buffer
+                byte[] newbuff = new byte[size+1024];
+                System.arraycopy(buff, 0, newbuff, 0, size);
+                buff = newbuff;
+                size += 1024;
+            }
+        }
+        if (buff[index-1] != '\n') {
+            throw new IOException(
+                Messages.getString("security.158")); //$NON-NLS-1$
+        }
+        // check and skip closing boundary delimiter prefix
+        // (first '-' was read)
+        for (int i=1; i<pemClose.length; i++) {
+            if (pemClose[i] != inStream.read()) {
+                throw new IOException(
+                    Messages.getString("security.15B1", //$NON-NLS-1$
+                        ((boundary_suffix == null) 
+                            ? "" 
+                            : new String(boundary_suffix)))); //$NON-NLS-1$
+            }
+        }
+        if (boundary_suffix == null) {
+            // read (skip) the trailing characters of 
+            // the closing PEM boundary delimiter
+            while (((ch = inStream.read()) != -1)
+                    && (ch != '\n') && (ch != '\r')) {
+            }
+        } else {
+            for (int i=0; i<boundary_suffix.length; i++) {
+                if (boundary_suffix[i] != inStream.read()) {
+                    throw new IOException(
+                        Messages.getString("security.15B1", //$NON-NLS-1$
+                            ((boundary_suffix == null) 
+                                ? "" 
+                                : new String(boundary_suffix)))); //$NON-NLS-1$
+                }
+            }
+        }
+        // skip trailing line breaks
+        inStream.mark(1);
+        while (((ch = inStream.read()) != -1) && (ch == '\n' || ch == '\r')) {
+            inStream.mark(1);
+        }
+        inStream.reset();
+        buff = Base64.decode(buff, index);
+        if (buff == null) {
+            throw new IOException(Messages.getString("security.159")); //$NON-NLS-1$
+        }
+        return buff;
+    };
+   
+    /**
+     * Reads the data of specified length from source 
+     * and returns it as an array.
+     * @return the byte array contained read data or 
+     * null if the stream contains not enough data
+     * @throws IOException if some I/O error has been occurred.
+     */
+    private static byte[] readBytes(InputStream source, int length) 
+                                                            throws IOException {
+        byte[] result = new byte[length];
+        for (int i=0; i<length; i++) {
+            int bytik = source.read();
+            if (bytik == -1) {
+                return null;
+            }
+            result[i] = (byte) bytik;
+        }
+        return result;
+    }
+
+    /**
+     * Returns the Certificate object corresponding to the provided encoding.
+     * Resulting object is retrieved from the cache 
+     * if it contains such correspondence 
+     * and is constructed on the base of encoding 
+     * and stored in the cache otherwise.
+     * @throws IOException if some decoding errors occur
+     * (in the case of cache miss).
+     */
+    private static Certificate getCertificate(byte[] encoding) 
+                                    throws CertificateException, IOException {
+        if (encoding.length < CERT_CACHE_SEED_LENGTH) {
+            throw new CertificateException(
+                    Messages.getString("security.152")); //$NON-NLS-1$
+        }
+        synchronized (CERT_CACHE) {
+            long hash = CERT_CACHE.getHash(encoding);
+            if (CERT_CACHE.contains(hash)) {
+                Certificate res = 
+                    (Certificate) CERT_CACHE.get(hash, encoding);
+                if (res != null) {
+                    return res;
+                }
+            }
+            Certificate res = new X509CertImpl(encoding);
+            CERT_CACHE.put(hash, encoding, res);
+            return res;
+        }
+    }
+
+    /**
+     * Returns the Certificate object corresponding to the encoding provided
+     * by the stream.
+     * Resulting object is retrieved from the cache 
+     * if it contains such correspondence 
+     * and is constructed on the base of encoding 
+     * and stored in the cache otherwise.
+     * @throws IOException if some decoding errors occur
+     * (in the case of cache miss).
+     */
+    private static Certificate getCertificate(InputStream inStream) 
+                                    throws CertificateException, IOException {
+        synchronized (CERT_CACHE) {
+            inStream.mark(CERT_CACHE_SEED_LENGTH);
+            // read the prefix of the encoding
+            byte[] buff = readBytes(inStream, CERT_CACHE_SEED_LENGTH);
+            inStream.reset();
+            if (buff == null) {
+                throw new CertificateException(
+                        Messages.getString("security.152")); //$NON-NLS-1$
+            }
+            long hash = CERT_CACHE.getHash(buff);
+            if (CERT_CACHE.contains(hash)) {
+                byte[] encoding = new byte[BerInputStream.getLength(buff)];
+                if (encoding.length < CERT_CACHE_SEED_LENGTH) {
+                    throw new CertificateException(
+                        Messages.getString("security.15B3")); //$NON-NLS-1$
+                }
+                inStream.read(encoding);
+                Certificate res = (Certificate) CERT_CACHE.get(hash, encoding);
+                if (res != null) {
+                    return res;
+                }
+                res = new X509CertImpl(encoding);
+                CERT_CACHE.put(hash, encoding, res);
+                return res;
+            } else {
+                inStream.reset();
+                Certificate res = new X509CertImpl(inStream);
+                CERT_CACHE.put(hash, res.getEncoded(), res);
+                return res;
+            }
+        }
+    }
+
+    /**
+     * Returns the CRL object corresponding to the provided encoding.
+     * Resulting object is retrieved from the cache 
+     * if it contains such correspondence 
+     * and is constructed on the base of encoding 
+     * and stored in the cache otherwise.
+     * @throws IOException if some decoding errors occur
+     * (in the case of cache miss).
+     */
+    private static CRL getCRL(byte[] encoding) 
+                                            throws CRLException, IOException {
+        if (encoding.length < CRL_CACHE_SEED_LENGTH) {
+            throw new CRLException(
+                    Messages.getString("security.152")); //$NON-NLS-1$
+        }
+        synchronized (CRL_CACHE) {
+            long hash = CRL_CACHE.getHash(encoding);
+            if (CRL_CACHE.contains(hash)) {
+                X509CRL res = (X509CRL) CRL_CACHE.get(hash, encoding);
+                if (res != null) {
+                    return res;
+                }
+            }
+            X509CRL res = new X509CRLImpl(encoding);
+            CRL_CACHE.put(hash, encoding, res);
+            return res;
+        }
+    }
+
+    /**
+     * Returns the CRL object corresponding to the encoding provided
+     * by the stream.
+     * Resulting object is retrieved from the cache 
+     * if it contains such correspondence 
+     * and is constructed on the base of encoding 
+     * and stored in the cache otherwise.
+     * @throws IOException if some decoding errors occur
+     * (in the case of cache miss).
+     */
+    private static CRL getCRL(InputStream inStream) 
+                                            throws CRLException, IOException {
+        synchronized (CRL_CACHE) {
+            inStream.mark(CRL_CACHE_SEED_LENGTH);
+            byte[] buff = readBytes(inStream, CRL_CACHE_SEED_LENGTH);
+            // read the prefix of the encoding
+            inStream.reset();
+            if (buff == null) {
+                throw new CRLException(
+                        Messages.getString("security.152")); //$NON-NLS-1$
+            }
+            long hash = CRL_CACHE.getHash(buff);
+            if (CRL_CACHE.contains(hash)) {
+                byte[] encoding = new byte[BerInputStream.getLength(buff)];
+                if (encoding.length < CRL_CACHE_SEED_LENGTH) {
+                    throw new CRLException(
+                        Messages.getString("security.15B4")); //$NON-NLS-1$
+                }
+                inStream.read(encoding);
+                CRL res = (CRL) CRL_CACHE.get(hash, encoding);
+                if (res != null) {
+                    return res;
+                }
+                res = new X509CRLImpl(encoding);
+                CRL_CACHE.put(hash, encoding, res);
+                return res;
+            } else {
+                X509CRL res = new X509CRLImpl(inStream);
+                CRL_CACHE.put(hash, res.getEncoded(), res);
+                return res;
+            }
+        }
+    }
+
+    /*
+     * This class extends any existing input stream with
+     * mark functionality. It acts as a wrapper over the
+     * stream and supports reset to the
+     * marked state with readlimit no more than BUFF_SIZE.
+     */
+    private static class RestoringInputStream extends InputStream {
+
+        // wrapped input stream
+        private final InputStream inStream;
+        // specifies how much of the read data is buffered
+        // after the mark has been set up
+        private static final int BUFF_SIZE = 32;
+        // buffer to keep the bytes read after the mark has been set up
+        private final int[] buff = new int[BUFF_SIZE*2];
+        // position of the next byte to read,
+        // the value of -1 indicates that the buffer is not used
+        // (mark was not set up or was invalidated, or reset to the marked
+        // position has been done and all the buffered data was read out)
+        private int pos = -1;
+        // position of the last buffered byte
+        private int bar = 0;
+        // position in the buffer where the mark becomes invalidated
+        private int end = 0;
+
+        /**
+         * Creates the mark supporting wrapper over the stream.
+         */
+        public RestoringInputStream(InputStream inStream) {
+            this.inStream = inStream;
+        }
+
+        /**
+         * @see java.io.InputStream#available()
+         * method documentation for more info
+         */
+        public int available() throws IOException {
+            return (bar - pos) + inStream.available();
+        }
+
+        /**
+         * @see java.io.InputStream#close()
+         * method documentation for more info
+         */
+        public void close() throws IOException {
+            inStream.close();
+        }
+
+        /**
+         * @see java.io.InputStream#mark(int readlimit)
+         * method documentation for more info
+         */
+        public void mark(int readlimit) {
+            if (pos < 0) {
+                pos = 0;
+                bar = 0;
+                end = BUFF_SIZE - 1;
+            } else {
+                end = (pos + BUFF_SIZE - 1) % BUFF_SIZE;
+            }
+        }
+
+        /**
+         * @see java.io.InputStream#markSupported()
+         * method documentation for more info
+         */
+        public boolean markSupported() {
+            return true;
+        }
+
+        /**
+         * Reads the byte from the stream. If mark has been set up
+         * and was not invalidated byte is read from the underlying
+         * stream and saved into the buffer. If the current read position
+         * has been reset to the marked position and there are remaining
+         * bytes in the buffer, the byte is taken from it. In the other cases
+         * (if mark has been invalidated, or there are no buffered bytes)
+         * the byte is taken directly from the underlying stream and it is
+         * returned without saving to the buffer.
+         *
+         * @see java.io.InputStream#read()
+         * method documentation for more info
+         */
+        public int read() throws IOException {
+            // if buffer is currently used
+            if (pos >= 0) {
+                // current position in the buffer
+                int cur = pos % BUFF_SIZE;
+                // check whether the buffer contains the data to be read
+                if (cur < bar) {
+                    // return the data from the buffer
+                    pos++;
+                    return buff[cur];
+                }
+                // check whether buffer has free space
+                if (cur != end) {
+                    // it has, so read the data from the wrapped stream
+                    // and place it in the buffer
+                    buff[cur] = inStream.read();
+                    bar = cur+1;
+                    pos++;
+                    return buff[cur];
+                } else {
+                    // buffer if full and can not operate
+                    // any more, so invalidate the mark position
+                    // and turn off the using of buffer
+                    pos = -1;
+                }
+            }
+            // buffer is not used, so return the data from the wrapped stream
+            return inStream.read();
+        }
+
+        /**
+         * @see java.io.InputStream#read(byte[] b)
+         * method documentation for more info
+         */
+        public int read(byte[] b) throws IOException {
+            return read(b, 0, b.length);
+        }
+
+        /**
+         * @see java.io.InputStream#read(byte[] b, int off, int len)
+         * method documentation for more info
+         */
+        public int read(byte[] b, int off, int len) throws IOException {
+            int read_b;
+            int i;
+            for (i=0; i<len; i++) {
+                if ((read_b = read()) == -1) {
+                    return (i == 0) ? -1 : i;
+                }
+                b[off+i] = (byte) read_b;
+            }
+            return i;
+        }
+
+        /**
+         * @see java.io.InputStream#reset()
+         * method documentation for more info
+         */
+        public void reset() throws IOException {
+            if (pos >= 0) {
+                pos = (end + 1) % BUFF_SIZE;
+            } else {
+                throw new IOException(
+                        Messages.getString("security.15A")); //$NON-NLS-1$
+            }
+        }
+
+        /**
+         * @see java.io.InputStream#skip(long n)
+         * method documentation for more info
+         */
+        public long skip(long n) throws IOException {
+            if (pos >= 0) {
+                long i = 0;
+                int av = available();
+                if (av < n) {
+                    n = av;
+                }
+                while ((i < n) && (read() != -1)) {
+                    i++;
+                }
+                return i;
+            } else {
+                return inStream.skip(n);
+            }
+        }
+    }
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/provider/cert/X509CertImpl.java b/libcore/security/src/main/java/org/apache/harmony/security/provider/cert/X509CertImpl.java
new file mode 100644
index 0000000..09b437c
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/provider/cert/X509CertImpl.java
@@ -0,0 +1,636 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.provider.cert;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.internal.nls.Messages;
+import org.apache.harmony.security.utils.AlgNameMapper;
+import org.apache.harmony.security.x509.Certificate;
+import org.apache.harmony.security.x509.Extension;
+import org.apache.harmony.security.x509.Extensions;
+import org.apache.harmony.security.x509.TBSCertificate;
+import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl;
+
+/**
+ * This class is an implementation of X509Certificate. It wraps
+ * the instance of org.apache.harmony.security.x509.Certificate
+ * built on the base of provided ASN.1 DER encoded form of
+ * Certificate structure (as specified in RFC 3280
+ * http://www.ietf.org/rfc/rfc3280.txt).
+ * @see org.apache.harmony.security.x509.Certificate
+ * @see java.security.cert.X509Certificate
+ */
+public class X509CertImpl extends X509Certificate {
+
+    /**
+     * @serial
+     */
+    private static final long serialVersionUID = 2972248729446736154L;
+
+    // the core object to be wrapped in X509Certificate
+    private final Certificate certificate;
+
+    // to speed up access to the info, the following fields
+    // cache values retrieved from the certificate object
+    private final TBSCertificate tbsCert;
+    private final Extensions extensions;
+    private long notBefore = -1;
+    private long notAfter;
+    private BigInteger serialNumber;
+    private X500Principal issuer;
+    private X500Principal subject;
+    private byte[] tbsCertificate;
+    private byte[] signature;
+    private String sigAlgName;
+    private String sigAlgOID;
+    private byte[] sigAlgParams;
+    // indicates whether the signature algorithm parameters are null
+    private boolean nullSigAlgParams;
+    private PublicKey publicKey;
+
+    // encoding of the certificate
+    private byte[] encoding;
+
+    //
+    // ---------------------- Constructors -------------------------------
+    //
+
+    /**
+     * Constructs the instance on the base of ASN.1 encoded
+     * form of X.509 certificate provided via stream parameter.
+     * @param in input stream containing ASN.1 encoded form of certificate.
+     * @throws CertificateException if some decoding problems occur.
+     */
+    public X509CertImpl(InputStream in) throws CertificateException {
+        try {
+            // decode the Certificate object
+            this.certificate = (Certificate) Certificate.ASN1.decode(in);
+            // cache the values of TBSCertificate and Extensions
+            this.tbsCert = certificate.getTbsCertificate();
+            this.extensions = tbsCert.getExtensions();
+        } catch (IOException e) {
+            throw new CertificateException(e);
+        }
+    }
+
+    /**
+     * Constructs the instance on the base of existing Certificate object to
+     * be wrapped.
+     */
+    public X509CertImpl(Certificate certificate) {
+        this.certificate = certificate;
+        // cache the values of TBSCertificate and Extensions
+        this.tbsCert = certificate.getTbsCertificate();
+        this.extensions = tbsCert.getExtensions();
+    }
+
+    /**
+     * Constructs the instance on the base of ASN.1 encoded
+     * form of X.509 certificate provided via array of bytes.
+     * @param encoding byte array containing ASN.1 encoded form of certificate.
+     * @throws IOException if some decoding problems occur.
+     */
+    public X509CertImpl(byte[] encoding) throws IOException {
+        this((Certificate) Certificate.ASN1.decode(encoding));
+    }
+
+    //
+    // ----------------- Public methods implementations ------------------
+    //
+
+    /**
+     * @see java.security.cert.X509Certificate#checkValidity()
+     * method documentation for more information.
+     */
+    public void checkValidity() throws CertificateExpiredException,
+                                       CertificateNotYetValidException {
+        if (notBefore == -1) {
+            // retrieve and cache the value of validity period
+            notBefore = tbsCert.getValidity().getNotBefore().getTime();
+            notAfter = tbsCert.getValidity().getNotAfter().getTime();
+        }
+        long time = System.currentTimeMillis();
+        if (time < notBefore) {
+            throw new CertificateNotYetValidException();
+        }
+        if (time > notAfter) {
+            throw new CertificateExpiredException();
+        }
+    }
+
+    /**
+     * @see java.security.cert.X509Certificate#checkValidity(Date)
+     * method documentation for more information.
+     */
+    public void checkValidity(Date date)
+                                throws CertificateExpiredException,
+                                       CertificateNotYetValidException {
+        if (notBefore == -1) {
+            // retrieve and cache the value of validity period
+            notBefore = tbsCert.getValidity().getNotBefore().getTime();
+            notAfter = tbsCert.getValidity().getNotAfter().getTime();
+        }
+        long time = date.getTime();
+        if (time < notBefore) {
+            throw new CertificateNotYetValidException("current time: " + date
+                + ", validation time: " + new Date(notBefore));
+        }
+        if (time > notAfter) {
+            throw new CertificateExpiredException("current time: " + date
+                + ", expiration time: " + new Date(notAfter));
+        }
+    }
+
+    /**
+     * @see java.security.cert.X509Certificate#getVersion()
+     * method documentation for more information.
+     */
+    public int getVersion() {
+        return tbsCert.getVersion() + 1;
+    }
+
+    /**
+     * @see java.security.cert.X509Certificate#getSerialNumber()
+     * method documentation for more information.
+     */
+    public BigInteger getSerialNumber() {
+        if (serialNumber == null) {
+            serialNumber = tbsCert.getSerialNumber();
+        }
+        return serialNumber;
+    }
+
+    /**
+     * @see java.security.cert.X509Certificate#getIssuerDN()
+     * method documentation for more information.
+     */
+    public Principal getIssuerDN() {
+        if (issuer == null) {
+            // retrieve the issuer's principal
+            issuer = tbsCert.getIssuer().getX500Principal();
+        }
+        return issuer;
+    }
+
+    /**
+     * @see java.security.cert.X509Certificate#getIssuerX500Principal()
+     * method documentation for more information.
+     */
+    public X500Principal getIssuerX500Principal() {
+        if (issuer == null) {
+            // retrieve the issuer's principal
+            issuer = tbsCert.getIssuer().getX500Principal();
+        }
+        return issuer;
+    }
+
+    /**
+     * @see java.security.cert.X509Certificate#getSubjectDN()
+     * method documentation for more information.
+     */
+    public Principal getSubjectDN() {
+        if (subject == null) {
+            // retrieve the subject's principal
+            subject = tbsCert.getSubject().getX500Principal();
+        }
+        return subject;
+    }
+
+    /**
+     * @see java.security.cert.X509Certificate#getSubjectX500Principal()
+     * method documentation for more information.
+     */
+    public X500Principal getSubjectX500Principal() {
+        if (subject == null) {
+            // retrieve the subject's principal
+            subject = tbsCert.getSubject().getX500Principal();
+        }
+        return subject;
+    }
+
+    /**
+     * @see java.security.cert.X509Certificate#getNotBefore()
+     * method documentation for more information.
+     */
+    public Date getNotBefore() {
+        if (notBefore == -1) {
+            // the value was not retrieved from the certificate, do it:
+            notBefore = tbsCert.getValidity().getNotBefore().getTime();
+            notAfter = tbsCert.getValidity().getNotAfter().getTime();
+        }
+        return new Date(notBefore);
+    }
+
+    /**
+     * @see java.security.cert.X509Certificate#getNotAfter()
+     * method documentation for more information.
+     */
+    public Date getNotAfter() {
+        if (notBefore == -1) {
+            // the value was not retrieved from the certificate, do it:
+            notBefore = tbsCert.getValidity().getNotBefore().getTime();
+            notAfter = tbsCert.getValidity().getNotAfter().getTime();
+        }
+        return new Date(notAfter);
+    }
+
+    /**
+     * @see java.security.cert.X509Certificate#getTBSCertificate()
+     * method documentation for more information.
+     */
+    public byte[] getTBSCertificate()
+                        throws CertificateEncodingException {
+        if (tbsCertificate == null) {
+            // retrieve the encoded form of the TBSCertificate structure
+            tbsCertificate = tbsCert.getEncoded();
+        }
+        byte[] result = new byte[tbsCertificate.length];
+        System.arraycopy(tbsCertificate, 0, result, 0, tbsCertificate.length);
+        return result;
+    }
+
+    /**
+     * @see java.security.cert.X509Certificate#getSignature()
+     * method documentation for more information.
+     */
+    public byte[] getSignature() {
+        if (signature == null) {
+            // retrieve the value of the signature
+            signature = certificate.getSignatureValue();
+        }
+        byte[] result = new byte[signature.length];
+        System.arraycopy(signature, 0, result, 0, signature.length);
+        return result;
+    }
+
+    /**
+     * @see java.security.cert.X509Certificate#getSigAlgName()
+     * method documentation for more information.
+     */
+    public String getSigAlgName() {
+        if (sigAlgOID == null) {
+            // if info was not retrieved (and cached), do it:
+            sigAlgOID = tbsCert.getSignature().getAlgorithm();
+            // retrieve the name of the signing algorithm
+            sigAlgName = AlgNameMapper.map2AlgName(sigAlgOID);
+            if (sigAlgName == null) {
+                // if could not be found, use OID as a name
+                sigAlgName = sigAlgOID;
+            }
+        }
+        return sigAlgName;
+    }
+
+    /**
+     * @see java.security.cert.X509Certificate#getSigAlgOID()
+     * method documentation for more information.
+     */
+    public String getSigAlgOID() {
+        if (sigAlgOID == null) {
+            // if info was not retrieved (and cached), do it:
+            sigAlgOID = tbsCert.getSignature().getAlgorithm();
+            // retrieve the name of the signing algorithm
+            sigAlgName = AlgNameMapper.map2AlgName(sigAlgOID);
+            if (sigAlgName == null) {
+                // if could not be found, use OID as a name
+                sigAlgName = sigAlgOID;
+            }
+        }
+        return sigAlgOID;
+    }
+
+    /**
+     * @see java.security.cert.X509Certificate#getSigAlgParams()
+     * method documentation for more information.
+     */
+    public byte[] getSigAlgParams() {
+        if (nullSigAlgParams) {
+            return null;
+        }
+        if (sigAlgParams == null) {
+            sigAlgParams = tbsCert.getSignature().getParameters();
+            if (sigAlgParams == null) {
+                nullSigAlgParams = true;
+                return null;
+            }
+        }
+        return sigAlgParams;
+    }
+
+    /**
+     * @see java.security.cert.X509Certificate#getIssuerUniqueID()
+     * method documentation for more information.
+     */
+    public boolean[] getIssuerUniqueID() {
+        return tbsCert.getIssuerUniqueID();
+    }
+
+    /**
+     * @see java.security.cert.X509Certificate#getSubjectUniqueID()
+     * method documentation for more information.
+     */
+    public boolean[] getSubjectUniqueID() {
+        return tbsCert.getSubjectUniqueID();
+    }
+
+    /**
+     * @see java.security.cert.X509Certificate#getKeyUsage()
+     * method documentation for more information.
+     */
+    public boolean[] getKeyUsage() {
+        if (extensions == null) {
+            return null;
+        }
+        return extensions.valueOfKeyUsage();
+    }
+
+    /**
+     * @see java.security.cert.X509Certificate#getExtendedKeyUsage()
+     * method documentation for more information.
+     */
+    public List/*<String>*/ getExtendedKeyUsage()
+                                throws CertificateParsingException {
+        if (extensions == null) {
+            return null;
+        }
+        try {
+            return extensions.valueOfExtendedKeyUsage();
+        } catch (IOException e) {
+            throw new CertificateParsingException(e);
+        }
+    }
+
+    /**
+     * @see java.security.cert.X509Certificate#getBasicConstraints()
+     * method documentation for more information.
+     */
+    public int getBasicConstraints() {
+        if (extensions == null) {
+            return Integer.MAX_VALUE;
+        }
+        return extensions.valueOfBasicConstrains();
+    }
+
+    /**
+     * @see java.security.cert.X509Certificate#getSubjectAlternativeNames()
+     * method documentation for more information.
+     */
+    public Collection/*<List<?>>*/ getSubjectAlternativeNames()
+                                throws CertificateParsingException {
+        if (extensions == null) {
+            return null;
+        }
+        try {
+            // Retrieve the extension value from the cached extensions object
+            // This extension is not checked for correctness during
+            // certificate generation, so now it can throw exception
+            return extensions.valueOfSubjectAlternativeName();
+        } catch (IOException e) {
+            throw new CertificateParsingException(e);
+        }
+    }
+
+    /**
+     * @see java.security.cert.X509Certificate#getIssuerAlternativeNames()
+     * method documentation for more information.
+     */
+    public Collection/*FIXME <List<?>>*/ getIssuerAlternativeNames()
+                                throws CertificateParsingException {
+        if (extensions == null) {
+            return null;
+        }
+        try {
+            // Retrieve the extension value from the cached extensions object
+            // This extension is not checked for correctness during
+            // certificate generation, so now it can throw exception
+            return extensions.valueOfIssuerAlternativeName();
+        } catch (IOException e) {
+            throw new CertificateParsingException(e);
+        }
+    }
+
+    //
+    // ----- java.security.cert.Certificate methods implementations ------
+    //
+
+    /**
+     * @see java.security.cert.Certificate#getEncoded()
+     * method documentation for more information.
+     */
+    public byte[] getEncoded() throws CertificateEncodingException {
+        if (encoding == null) {
+            encoding = certificate.getEncoded();
+        }
+        byte[] result = new byte[encoding.length];
+        System.arraycopy(encoding, 0, result, 0, encoding.length);
+        return result;
+    }
+
+    /**
+     * @see java.security.cert.Certificate#getPublicKey()
+     * method documentation for more information.
+     */
+    public PublicKey getPublicKey() {
+        if (publicKey == null) {
+            // retrieve the public key from SubjectPublicKeyInfo
+            // substructure of X.509 certificate
+            publicKey = tbsCert.getSubjectPublicKeyInfo().getPublicKey();
+        }
+        return publicKey;
+    }
+
+    /**
+     * @see java.security.cert.Certificate#toString()
+     * method documentation for more information.
+     */
+    public String toString() {
+        return certificate.toString();
+    }
+
+    /**
+     * Verifies the signature of the certificate.
+     * @see java.security.cert.Certificate#verify(PublicKey)
+     * method documentation for more information.
+     */
+    public void verify(PublicKey key)
+                         throws CertificateException, NoSuchAlgorithmException,
+                                InvalidKeyException, NoSuchProviderException,
+                                SignatureException {
+
+        // BEGIN android-added
+        if (getSigAlgName().endsWith("withRSA")) {
+            fastVerify(key);
+            return;
+        }
+        // END android-added
+
+        Signature signature = Signature.getInstance(getSigAlgName());
+        signature.initVerify(key);
+        // retrieve the encoding of the TBSCertificate structure
+        if (tbsCertificate == null) {
+            tbsCertificate = tbsCert.getEncoded();
+        }
+        // compute and verify the signature
+        signature.update(tbsCertificate, 0, tbsCertificate.length);
+        if (!signature.verify(certificate.getSignatureValue())) {
+            throw new SignatureException(Messages.getString("security.15C")); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Verifies the signature of the certificate.
+     * @see java.security.cert.Certificate#verify(PublicKey,String)
+     * method documentation for more information.
+     */
+    public void verify(PublicKey key, String sigProvider)
+                         throws CertificateException, NoSuchAlgorithmException,
+                                InvalidKeyException, NoSuchProviderException,
+                                SignatureException {
+        
+        // BEGIN android-added
+        if (getSigAlgName().endsWith("withRSA")) {
+            fastVerify(key);
+            return;
+        }
+        // END android-added
+        
+        Signature signature =
+            Signature.getInstance(getSigAlgName(), sigProvider);
+        signature.initVerify(key);
+        // retrieve the encoding of the TBSCertificate structure
+        if (tbsCertificate == null) {
+            tbsCertificate = tbsCert.getEncoded();
+        }
+        // compute and verify the signature
+        signature.update(tbsCertificate, 0, tbsCertificate.length);
+        if (!signature.verify(certificate.getSignatureValue())) {
+            throw new SignatureException(Messages.getString("security.15C")); //$NON-NLS-1$
+        }
+    }
+
+    // BEGIN android-added
+    /**
+     * Implements a faster RSA verification method that delegates to OpenSSL
+     * native code. In all other aspects it behaves just like the ordinary
+     * {@link verify} method.
+     * 
+     * @param key The RSA public key to use
+     * 
+     * @throws SignatureException If the verification fails.
+     */
+    private void fastVerify(PublicKey key) throws SignatureException {
+        RSAPublicKey rsaKey = (RSAPublicKey) key;
+        
+        String algorithm = getSigAlgName();
+        int i = algorithm.indexOf("with");
+        algorithm = algorithm.substring(i + 4) + "-" + algorithm.substring(0, i);
+        
+        if (tbsCertificate == null) {
+            tbsCertificate = tbsCert.getEncoded();
+        }
+
+        byte[] sig = certificate.getSignatureValue();
+        if (!OpenSSLSocketImpl.verifySignature(tbsCertificate, sig, algorithm, rsaKey)) {
+            throw new SignatureException(Messages.getString("security.15C")); //$NON-NLS-1$
+        }
+    }
+    // END android-added
+
+    //
+    // ----- java.security.cert.X509Extension methods implementations ----
+    //
+
+    /**
+     * @see java.security.cert.X509Extension#getNonCriticalExtensionOIDs()
+     * method documentation for more information.
+     */
+    public Set getNonCriticalExtensionOIDs() {
+        if (extensions == null) {
+            return null;
+        }
+        // retrieve the info from the cached extensions object
+        return extensions.getNonCriticalExtensions();
+    }
+
+    /**
+     * @see java.security.cert.X509Extension#getCriticalExtensionOIDs()
+     * method documentation for more information.
+     */
+    public Set getCriticalExtensionOIDs() {
+        if (extensions == null) {
+            return null;
+        }
+        // retrieve the info from the cached extensions object
+        return extensions.getCriticalExtensions();
+    }
+
+    /**
+     * @see java.security.cert.X509Extension#getExtensionValue(String)
+     * method documentation for more information.
+     */
+    public byte[] getExtensionValue(String oid) {
+        if (extensions == null) {
+            return null;
+        }
+        // retrieve the info from the cached extensions object
+        Extension ext = extensions.getExtensionByOID(oid);
+        return (ext == null) ? null : ext.getRawExtnValue();
+    }
+
+    /**
+     * @see java.security.cert.X509Extension#hasUnsupportedCriticalExtension()
+     * method documentation for more information.
+     */
+    public boolean hasUnsupportedCriticalExtension() {
+        if (extensions == null) {
+            return false;
+        }
+        // retrieve the info from the cached extensions object
+        return extensions.hasUnsupportedCritical();
+    }
+
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/provider/cert/X509CertPathImpl.java b/libcore/security/src/main/java/org/apache/harmony/security/provider/cert/X509CertPathImpl.java
new file mode 100644
index 0000000..2234ce4
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/provider/cert/X509CertPathImpl.java
@@ -0,0 +1,433 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.provider.cert;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.cert.CertPath;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.harmony.security.asn1.ASN1Any;
+import org.apache.harmony.security.asn1.ASN1Explicit;
+import org.apache.harmony.security.asn1.ASN1Implicit;
+import org.apache.harmony.security.asn1.ASN1Oid;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1SequenceOf;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.internal.nls.Messages;
+import org.apache.harmony.security.pkcs7.ContentInfo;
+import org.apache.harmony.security.pkcs7.SignedData;
+import org.apache.harmony.security.x509.Certificate;
+
+/**
+ * This class is an implementation of X.509 CertPath. This implementation
+ * provides ability to create the instance of X.509 Certification Path
+ * by several means:<br>
+ *
+ * &nbsp;  1. It can be created over the list of X.509 certificates
+ * (implementations of X509Certificate class) provided in constructor.<br>
+ *
+ * &nbsp;  2. It can be created by means of <code>getInstance</code> methods
+ * on the base of the following ASN.1 DER encoded forms:<br>
+ *
+ * &nbsp;&nbsp;  - PkiPath as defined in
+ * ITU-T Recommendation X.509(2000) Corrigendum 1(2001)
+ * (can be seen at
+ * ftp://ftp.bull.com/pub/OSIdirectory/DefectResolution/TechnicalCorrigenda/ApprovedTechnicalCorrigendaToX.509/8%7CX.509-TC1(4th).pdf)
+ * <br>
+ * &nbsp;&nbsp;  - PKCS #7 SignedData object provided in the form of
+ * ContentInfo structure. CertPath object is generated on the base of
+ * certificates presented in <code>certificates</code> field of the SignedData
+ * object which in its turn is retrieved from ContentInfo structure.
+ * (see http://www.ietf.org/rfc/rfc2315.txt
+ * for more info on PKCS #7)
+ * <br>
+ * &nbsp;
+ */
+public class X509CertPathImpl extends CertPath {
+
+    /**
+     * @serial
+     */
+    private static final long serialVersionUID = 7989755106209515436L;
+
+    // supported encoding types:
+    public static final int PKI_PATH = 0;
+    public static final int PKCS7 = 1;
+
+    // supported encoding names
+    private static final String[] encodingsArr =
+                                        new String[] {"PkiPath", "PKCS7"}; //$NON-NLS-1$ //$NON-NLS-2$
+    static final List encodings = Collections.unmodifiableList(
+                                            Arrays.asList(encodingsArr));
+    // the list of certificates representing this certification path
+    private final List certificates;
+    // PkiPath encoding of the certification path
+    private byte[] pkiPathEncoding;
+    // PKCS7 encoding of the certification path
+    private byte[] pkcs7Encoding;
+
+    /**
+     * Creates an instance of X.509 Certification Path over the specified
+     * list of certificates.
+     * @throws CertificateException if some of the object in the list
+     * is not an instance of subclass of X509Certificate.
+     */
+    public X509CertPathImpl(List certs) throws CertificateException {
+        super("X.509"); //$NON-NLS-1$
+        int size = certs.size();
+        certificates = new ArrayList(size);
+        for (int i=0; i<size; i++) {
+            Object cert = certs.get(i);
+            if (!(cert instanceof X509Certificate) ) {
+                throw new CertificateException(
+                        Messages.getString("security.15D")); //$NON-NLS-1$
+            }
+            certificates.add(cert);
+        }
+    }
+
+    /*
+     * Internally used constructor.
+     * Creates an X.509 Certification Path over the specified
+     * list of certificates and their encoded form of specified type.
+     * @param certs - the list of certificates
+     * @param type - the type of the encoded form on the base of which
+     * this list of certificates had been built.
+     * @param encoding - encoded form of certification path.
+     */
+    private X509CertPathImpl(List certs, int type, byte[] encoding) {
+        super("X.509"); //$NON-NLS-1$
+        if (type == PKI_PATH) {
+            this.pkiPathEncoding = encoding;
+        } else { // PKCS7
+            this.pkcs7Encoding = encoding;
+        }
+        // We do not need the type check and list cloning here,
+        // because it has been done during decoding.
+        certificates = certs;
+    }
+
+    /**
+     * Generates certification path object on the base of PkiPath
+     * encoded form provided via input stream.
+     * @throws CertificateException if some problems occurred during
+     * the decoding.
+     */
+    public static X509CertPathImpl getInstance(InputStream in)
+                                        throws CertificateException {
+        try {
+            return (X509CertPathImpl) ASN1.decode(in);
+        } catch (IOException e) {
+            throw new CertificateException(Messages.getString("security.15E", //$NON-NLS-1$
+                    e.getMessage()));
+        }
+    }
+
+    /**
+     * Generates certification path object on the base of encoding provided via
+     * input stream. The format of provided encoded form is specified by
+     * parameter <code>encoding</code>.
+     * @throws CertificateException if specified encoding form is not supported,
+     * or some problems occurred during the decoding.
+     */
+    public static X509CertPathImpl getInstance(InputStream in, String encoding)
+        throws CertificateException {
+        if (!encodings.contains(encoding)) {
+            throw new CertificateException(
+                    Messages.getString("security.15F", encoding)); //$NON-NLS-1$
+        }
+        try {
+            if (encodingsArr[0].equals(encoding)) {
+                // generate the object from PkiPath encoded form
+                return (X509CertPathImpl) ASN1.decode(in);
+            } else {
+                // generate the object from PKCS #7 encoded form
+                ContentInfo ci = (ContentInfo) ContentInfo.ASN1.decode(in);
+                SignedData sd = ci.getSignedData();
+                if (sd == null) {
+                    throw new CertificateException(
+                        Messages.getString("security.160")); //$NON-NLS-1$
+                }
+                List certs = sd.getCertificates();
+                if (certs == null) {
+                    // empty chain of certificates
+                    certs = new ArrayList();
+                }
+                List result = new ArrayList();
+                for (int i=0; i<certs.size(); i++) {
+                    result.add(new X509CertImpl((Certificate) certs.get(i)));
+                }
+                return new X509CertPathImpl(result, PKCS7, ci.getEncoded());
+            }
+        } catch (IOException e) {
+            throw new CertificateException(Messages.getString("security.15E", //$NON-NLS-1$
+                    e.getMessage()));
+        }
+    }
+
+    /**
+     * Generates certification path object on the base of PkiPath
+     * encoded form provided via array of bytes.
+     * @throws CertificateException if some problems occurred during
+     * the decoding.
+     */
+    public static X509CertPathImpl getInstance(byte[] in)
+                                        throws CertificateException {
+        try {
+            return (X509CertPathImpl) ASN1.decode(in);
+        } catch (IOException e) {
+            throw new CertificateException(Messages.getString("security.15E", //$NON-NLS-1$
+                    e.getMessage()));
+        }
+    }
+
+    /**
+     * Generates certification path object on the base of encoding provided via
+     * array of bytes. The format of provided encoded form is specified by
+     * parameter <code>encoding</code>.
+     * @throws CertificateException if specified encoding form is not supported,
+     * or some problems occurred during the decoding.
+     */
+    public static X509CertPathImpl getInstance(byte[] in, String encoding)
+        throws CertificateException {
+        if (!encodings.contains(encoding)) {
+            throw new CertificateException(
+                    Messages.getString("security.15F", encoding)); //$NON-NLS-1$
+        }
+        try {
+            if (encodingsArr[0].equals(encoding)) {
+                // generate the object from PkiPath encoded form
+                return (X509CertPathImpl) ASN1.decode(in);
+            } else {
+                // generate the object from PKCS #7 encoded form
+                ContentInfo ci = (ContentInfo) ContentInfo.ASN1.decode(in);
+                SignedData sd = ci.getSignedData();
+                if (sd == null) {
+                    throw new CertificateException(
+                        Messages.getString("security.160")); //$NON-NLS-1$
+                }
+                List certs = sd.getCertificates();
+                if (certs == null) {
+                    certs = new ArrayList();
+                }
+                List result = new ArrayList();
+                for (int i=0; i<certs.size(); i++) {
+                    result.add(new X509CertImpl((Certificate) certs.get(i)));
+                }
+                return new X509CertPathImpl(result, PKCS7, ci.getEncoded());
+            }
+        } catch (IOException e) {
+            throw new CertificateException(Messages.getString("security.15E", //$NON-NLS-1$
+                    e.getMessage()));
+        }
+    }
+
+    // ---------------------------------------------------------------------
+    // ---- java.security.cert.CertPath abstract method implementations ----
+    // ---------------------------------------------------------------------
+
+    /**
+     * @see java.security.cert.CertPath#getCertificates()
+     * method documentation for more info
+     */
+    public List getCertificates() {
+        return Collections.unmodifiableList(certificates);
+    }
+
+    /**
+     * @see java.security.cert.CertPath#getEncoded()
+     * method documentation for more info
+     */
+    public byte[] getEncoded() throws CertificateEncodingException {
+        if (pkiPathEncoding == null) {
+            pkiPathEncoding = ASN1.encode(this);
+        }
+        byte[] result = new byte[pkiPathEncoding.length];
+        System.arraycopy(pkiPathEncoding, 0, result, 0, pkiPathEncoding.length);
+        return result;
+    }
+
+    /**
+     * @see java.security.cert.CertPath#getEncoded(String)
+     * method documentation for more info
+     */
+    public byte[] getEncoded(String encoding)
+        throws CertificateEncodingException {
+        if (!encodings.contains(encoding)) {
+            throw new CertificateEncodingException(
+                    Messages.getString("security.15F", encoding)); //$NON-NLS-1$
+        }
+        if (encodingsArr[0].equals(encoding)) {
+            // PkiPath encoded form
+            return getEncoded();
+        } else {
+            // PKCS7 encoded form
+            if (pkcs7Encoding == null) {
+                pkcs7Encoding = PKCS7_SIGNED_DATA_OBJECT.encode(this);
+            }
+            byte[] result = new byte[pkcs7Encoding.length];
+            System.arraycopy(pkcs7Encoding, 0, result, 0,
+                                        pkcs7Encoding.length);
+            return result;
+        }
+    }
+
+    /**
+     * @see java.security.cert.CertPath#getEncodings()
+     * method documentation for more info
+     */
+    public Iterator getEncodings() {
+        return encodings.iterator();
+    }
+
+    /**
+     * ASN.1 DER Encoder/Decoder for PkiPath structure.
+     */
+    public static ASN1SequenceOf ASN1 =
+                                    new ASN1SequenceOf(ASN1Any.getInstance()) {
+
+        /**
+         * Builds the instance of X509CertPathImpl on the base of the list
+         * of ASN.1 encodings of X.509 certificates provided via
+         * PkiPath structure.
+         * This method participates in decoding process.
+         */
+        public Object getDecodedObject(BerInputStream in) throws IOException {
+            // retrieve the decoded content
+            List encodings = (List) in.content;
+            int size = encodings.size();
+            List certificates = new ArrayList(size);
+            for (int i=0; i<size; i++) {
+                // create the X.509 certificate on the base of its encoded form
+                // and add it to the list.
+                certificates.add(
+                    new X509CertImpl((Certificate)
+                        Certificate.ASN1.decode((byte[]) encodings.get(i))));
+            }
+            // create and return the resulting object
+            return new X509CertPathImpl(
+                    certificates, PKI_PATH, in.getEncoded());
+        }
+
+        /**
+         * Returns the Collection of the encoded form of certificates contained
+         * in the X509CertPathImpl object to be encoded.
+         * This method participates in encoding process.
+         */
+        public Collection getValues(Object object) {
+            // object to be encoded
+            X509CertPathImpl cp = (X509CertPathImpl) object;
+            // if it has no certificates in it - create the sequence of size 0
+            if (cp.certificates == null) {
+                return new ArrayList();
+            }
+            int size = cp.certificates.size();
+            List encodings = new ArrayList(size);
+            try {
+                for (int i=0; i<size; i++) {
+                    // get the encoded form of certificate and place it into the
+                    // list to be encoded in PkiPath format
+                    encodings.add(((X509Certificate)
+                                cp.certificates.get(i)).getEncoded());
+                }
+            } catch (CertificateEncodingException e) {
+                throw new IllegalArgumentException(Messages.getString("security.161")); //$NON-NLS-1$
+            }
+            return encodings;
+        }
+    };
+    
+
+    //
+    // encoder for PKCS#7 SignedData
+    // it is assumed that only certificate field is important
+    // all other fields contain precalculated encodings:
+    //
+    // encodes X509CertPathImpl objects
+    //
+    private static final ASN1Sequence ASN1_SIGNED_DATA = new ASN1Sequence(
+            new ASN1Type[] {
+                    // version ,digestAlgorithms, content info
+                    ASN1Any.getInstance(),
+                    // certificates
+                    new ASN1Implicit(0, ASN1),
+                    // set of crls is optional and is missed here
+                    ASN1Any.getInstance(),// signers info
+            }) {
+
+        // precalculated ASN.1 encodings for
+        // version ,digestAlgorithms, content info field of SignedData
+        private final byte[] PRECALCULATED_HEAD = new byte[] { 0x02, 0x01,
+                0x01,// version (v1)
+                0x31, 0x00,// empty set of DigestAlgorithms
+                0x30, 0x03, 0x06, 0x01, 0x00 // empty ContentInfo with oid=0
+        };
+
+        // precalculated empty set of SignerInfos
+        private final byte[] SIGNERS_INFO = new byte[] { 0x31, 0x00 };
+
+        protected void getValues(Object object, Object[] values) {
+            values[0] = PRECALCULATED_HEAD;
+            values[1] = object; // pass X509CertPathImpl object
+            values[2] = SIGNERS_INFO;
+        }
+
+        // stub to prevent using the instance as decoder
+        public Object decode(BerInputStream in) throws IOException {
+            throw new RuntimeException(
+                    "Invalid use of encoder for PKCS#7 SignedData object");
+        }
+    };
+    
+    private static final ASN1Sequence PKCS7_SIGNED_DATA_OBJECT = new ASN1Sequence(
+            new ASN1Type[] { ASN1Any.getInstance(), // contentType
+                    new ASN1Explicit(0, ASN1_SIGNED_DATA) // SignedData
+            }) {
+
+        // precalculated ASN.1 encoding for SignedData object oid
+        private final byte[] SIGNED_DATA_OID = ASN1Oid.getInstance().encode(
+                ContentInfo.SIGNED_DATA);
+
+        protected void getValues(Object object, Object[] values) {
+            values[0] = SIGNED_DATA_OID;
+            values[1] = object; // pass X509CertPathImpl object
+        }
+
+        // stub to prevent using the instance as decoder
+        public Object decode(BerInputStream in) throws IOException {
+            throw new RuntimeException(
+                    "Invalid use of encoder for PKCS#7 SignedData object");
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/CryptoProvider.java b/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/CryptoProvider.java
new file mode 100644
index 0000000..80b674b
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/CryptoProvider.java
@@ -0,0 +1,96 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.security.provider.crypto;
+
+import java.security.Provider;
+import java.security.AccessController;
+
+import org.apache.harmony.security.provider.crypto.RandomBitsSupplier;
+
+/**
+ * Implementation of Provider for SecureRandom, MessageDigest and Signature
+ * using a Secure Hash Algorithm, SHA-1;
+ * see SECURE HASH STANDARD, FIPS PUB 180-1 (http://www.itl.nist.gov/fipspubs/fip180-1.htm) <BR>
+ * <BR>
+ * The implementation supports "SHA1PRNG", "SHA-1" and "SHA1withDSA" algorithms described in
+ * JavaTM Cryptography Architecture, API Specification & Reference
+ */
+
+public final class CryptoProvider extends Provider {
+
+    private static final long serialVersionUID = 7991202868423459598L;
+
+    /**
+     * Creates a Provider and puts parameters
+     */
+    public CryptoProvider() {
+
+        super("Crypto", 1.0, //$NON-NLS-1$
+                "HARMONY (SHA1 digest; SecureRandom; SHA1withDSA signature)"); //$NON-NLS-1$
+
+        //  names of classes implementing services
+        final String MD_NAME = "org.apache.harmony.security.provider.crypto.SHA1_MessageDigestImpl"; //$NON-NLS-1$
+        final String SR_NAME = "org.apache.harmony.security.provider.crypto.SHA1PRNG_SecureRandomImpl"; //$NON-NLS-1$
+
+        final String SIGN_NAME = "org.apache.harmony.security.provider.crypto.SHA1withDSA_SignatureImpl"; //$NON-NLS-1$
+
+        final String SIGN_ALIAS = "SHA1withDSA"; //$NON-NLS-1$
+
+
+        final String KEYF_NAME = 
+                 "org.apache.harmony.security.provider.crypto.DSAKeyFactoryImpl"; //$NON-NLS-1$
+
+        AccessController.doPrivileged(new java.security.PrivilegedAction<Void>() {
+
+            public Void run() {
+
+                put("MessageDigest.SHA-1", MD_NAME); //$NON-NLS-1$
+                put("MessageDigest.SHA-1 ImplementedIn", "Software"); //$NON-NLS-1$ //$NON-NLS-2$
+                put("Alg.Alias.MessageDigest.SHA1", "SHA-1"); //$NON-NLS-1$ //$NON-NLS-2$
+                put("Alg.Alias.MessageDigest.SHA", "SHA-1"); //$NON-NLS-1$ //$NON-NLS-2$
+
+                if (RandomBitsSupplier.isServiceAvailable()) {
+                    put("SecureRandom.SHA1PRNG", SR_NAME); //$NON-NLS-1$
+                    put("SecureRandom.SHA1PRNG ImplementedIn", "Software"); //$NON-NLS-1$ //$NON-NLS-2$
+                }
+
+                put("Signature.SHA1withDSA", SIGN_NAME); //$NON-NLS-1$
+                put("Signature.SHA1withDSA ImplementedIn", "Software"); //$NON-NLS-1$ //$NON-NLS-2$
+                put("Alg.Alias.Signature.SHAwithDSA", SIGN_ALIAS); //$NON-NLS-1$
+                put("Alg.Alias.Signature.DSAwithSHA1", SIGN_ALIAS); //$NON-NLS-1$
+                put("Alg.Alias.Signature.SHA1/DSA", SIGN_ALIAS); //$NON-NLS-1$
+                put("Alg.Alias.Signature.SHA/DSA", SIGN_ALIAS); //$NON-NLS-1$
+                put("Alg.Alias.Signature.SHA-1/DSA", SIGN_ALIAS); //$NON-NLS-1$
+                put("Alg.Alias.Signature.DSA", SIGN_ALIAS); //$NON-NLS-1$
+                put("Alg.Alias.Signature.DSS", SIGN_ALIAS); //$NON-NLS-1$
+
+                put("Alg.Alias.Signature.OID.1.2.840.10040.4.3", SIGN_ALIAS); //$NON-NLS-1$
+                put("Alg.Alias.Signature.1.2.840.10040.4.3", SIGN_ALIAS); //$NON-NLS-1$
+                put("Alg.Alias.Signature.1.3.14.3.2.13", SIGN_ALIAS); //$NON-NLS-1$
+                put("Alg.Alias.Signature.1.3.14.3.2.27", SIGN_ALIAS); //$NON-NLS-1$
+
+                put("KeyFactory.DSA", KEYF_NAME); //$NON-NLS-1$
+                put("KeyFactory.DSA ImplementedIn", "Software"); //$NON-NLS-1$ //$NON-NLS-2$
+                put("Alg.Alias.KeyFactory.1.3.14.3.2.12", "DSA"); //$NON-NLS-1$ //$NON-NLS-2$
+                put("Alg.Alias.KeyFactory.1.2.840.10040.4.1", "DSA"); //$NON-NLS-1$ //$NON-NLS-2$
+
+                return null;
+            }
+        });
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/DSAKeyFactoryImpl.java b/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/DSAKeyFactoryImpl.java
new file mode 100644
index 0000000..af314ef
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/DSAKeyFactoryImpl.java
@@ -0,0 +1,229 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.security.provider.crypto;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAPrivateKeySpec;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+public class DSAKeyFactoryImpl extends KeyFactorySpi {
+
+    /**
+     * The method generates a DSAPrivateKey object from the provided key specification. 
+     *
+     * @param
+     *    keySpec - the specification (key material) for the DSAPrivateKey.
+     *
+     * @return
+     *    a DSAPrivateKey object
+     *
+     * @throws InvalidKeySpecException
+     *     if "keySpec" is neither DSAPrivateKeySpec nor PKCS8EncodedKeySpec
+     */
+    protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
+            throws InvalidKeySpecException {
+
+        if (keySpec != null) {
+            if (keySpec instanceof DSAPrivateKeySpec) {
+
+                return new DSAPrivateKeyImpl((DSAPrivateKeySpec) keySpec);
+            }
+            if (keySpec instanceof PKCS8EncodedKeySpec) {
+
+                return new DSAPrivateKeyImpl((PKCS8EncodedKeySpec) keySpec);
+            }
+        }
+        throw new InvalidKeySpecException(Messages.getString("security.19C")); //$NON-NLS-1$
+    }
+
+    /**
+     * The method generates a DSAPublicKey object from the provided key specification. 
+     *
+     * @param
+     *    keySpec - the specification (key material) for the DSAPublicKey.
+     *
+     * @return
+     *    a DSAPublicKey object
+     *
+     * @throws InvalidKeySpecException
+     *     if "keySpec" is neither DSAPublicKeySpec nor X509EncodedKeySpec
+     */
+    protected PublicKey engineGeneratePublic(KeySpec keySpec)
+            throws InvalidKeySpecException {
+
+        if (keySpec != null) {
+            if (keySpec instanceof DSAPublicKeySpec) {
+
+                return new DSAPublicKeyImpl((DSAPublicKeySpec) keySpec);
+            }
+            if (keySpec instanceof X509EncodedKeySpec) {
+
+                return new DSAPublicKeyImpl((X509EncodedKeySpec) keySpec);
+            }
+        }
+        throw new InvalidKeySpecException(Messages.getString("security.19D")); //$NON-NLS-1$
+    }
+
+    /**
+     * The method returns a specification (key material) of the given key object. 
+     * 'keySpec' identifies the specification class 
+     * in which the key material should be returned.
+     *
+     * If it is DSAPublicKeySpec.class, the key material should be returned 
+     * in an instance of the DSAPublicKeySpec class;
+     * if it is DSAPrivateKeySpec.class, the key material should be returned 
+     * in an instance of the DSAPrivateKeySpec class.
+     *
+     * @param
+     *    key - either DSAPrivateKey or DSAPublicKey
+     * @param
+     *    keySpec - either DSAPublicKeySpec.class or DSAPublicKeySpec.class
+     *
+     * @return
+     *    either DSAPublicKeySpec object or DSAPublicKeySpec object
+     *
+     * @throws InvalidKeySpecException
+     *     if "keySpec" is not s specification for DSAPublicKey or DSAPrivateKey
+     *
+     */
+    protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
+            throws InvalidKeySpecException {
+
+        BigInteger p, q, g, x, y;
+
+        if (key != null) {
+            if (keySpec == null) {
+                throw new NullPointerException(Messages
+                        .getString("security.19E")); //$NON-NLS-1$
+            }
+            if (key instanceof DSAPrivateKey) {
+                DSAPrivateKey privateKey = (DSAPrivateKey) key;
+
+                if (keySpec.equals(DSAPrivateKeySpec.class)) {
+
+                    x = privateKey.getX();
+
+                    DSAParams params = privateKey.getParams();
+
+                    p = params.getP();
+                    q = params.getQ();
+                    g = params.getG();
+
+                    return (T) (new DSAPrivateKeySpec(x, p, q, g));
+                }
+
+                if (keySpec.equals(PKCS8EncodedKeySpec.class)) {
+                    return (T) (new PKCS8EncodedKeySpec(key.getEncoded()));
+                }
+
+                throw new InvalidKeySpecException(Messages
+                        .getString("security.19C")); //$NON-NLS-1$
+            }
+
+            if (key instanceof DSAPublicKey) {
+                DSAPublicKey publicKey = (DSAPublicKey) key;
+
+                if (keySpec.equals(DSAPublicKeySpec.class)) {
+
+                    y = publicKey.getY();
+
+                    DSAParams params = publicKey.getParams();
+
+                    p = params.getP();
+                    q = params.getQ();
+                    g = params.getG();
+
+                    return (T) (new DSAPublicKeySpec(y, p, q, g));
+                }
+
+                if (keySpec.equals(X509EncodedKeySpec.class)) {
+                    return (T) (new X509EncodedKeySpec(key.getEncoded()));
+                }
+
+                throw new InvalidKeySpecException(Messages
+                        .getString("security.19D")); //$NON-NLS-1$
+            }
+        }
+        throw new InvalidKeySpecException(Messages.getString("security.19F")); //$NON-NLS-1$
+    }
+
+    /**
+     * The method generates a DSAPublicKey object from the provided key. 
+     *
+     * @param
+     *    key - a DSAPublicKey object or DSAPrivateKey object.
+     *
+     * @return
+     *    object of the same type as the "key" argument
+     *
+     * @throws InvalidKeyException
+     *     if "key" is neither DSAPublicKey nor DSAPrivateKey
+     */
+    protected Key engineTranslateKey(Key key) throws InvalidKeyException {
+
+        if (key != null) {
+            if (key instanceof DSAPrivateKey) {
+
+                DSAPrivateKey privateKey = (DSAPrivateKey) key;
+                DSAParams params = privateKey.getParams();
+
+                try {
+                    return engineGeneratePrivate(new DSAPrivateKeySpec(
+                            privateKey.getX(), params.getP(), params.getQ(),
+                            params.getG()));
+                } catch (InvalidKeySpecException e) {
+                    // Actually this exception shouldn't be thrown
+                    throw new InvalidKeyException(Messages.getString(
+                            "security.1A0", e)); //$NON-NLS-1$
+                }
+            }
+
+            if (key instanceof DSAPublicKey) {
+
+                DSAPublicKey publicKey = (DSAPublicKey) key;
+                DSAParams params = publicKey.getParams();
+
+                try {
+                    return engineGeneratePublic(new DSAPublicKeySpec(publicKey
+                            .getY(), params.getP(), params.getQ(), params
+                            .getG()));
+                } catch (InvalidKeySpecException e) {
+                    // Actually this exception shouldn't be thrown
+                    throw new InvalidKeyException(Messages.getString(
+                            "security.1A1", e)); //$NON-NLS-1$
+                }
+            }
+        }
+        throw new InvalidKeyException(Messages.getString("security.19F")); //$NON-NLS-1$
+    }
+
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/DSAPrivateKeyImpl.java b/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/DSAPrivateKeyImpl.java
new file mode 100644
index 0000000..17af038
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/DSAPrivateKeyImpl.java
@@ -0,0 +1,157 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+ /*
+  * TODO
+  * 1. The class extends the PrivateKeyImpl class in "org.apache.harmony.security" package.
+  *
+  * 2. See a compatibility with RI comments
+  *    in the below "DSAPrivateKeyImpl(PKCS8EncodedKeySpec keySpec)" constructor.
+  */
+
+
+package org.apache.harmony.security.provider.crypto;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.DSAPrivateKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+
+import org.apache.harmony.security.PrivateKeyImpl;
+import org.apache.harmony.security.asn1.ASN1Integer;
+import org.apache.harmony.security.internal.nls.Messages;
+import org.apache.harmony.security.pkcs8.PrivateKeyInfo;
+import org.apache.harmony.security.utils.AlgNameMapper;
+import org.apache.harmony.security.x509.AlgorithmIdentifier;
+
+/**
+ * The class provides DSAPrivateKey functionality by extending a class implementing PrivateKey
+ * and implementing methods defined in both interfaces, DSAKey and DSAPrivateKey
+ */
+public class DSAPrivateKeyImpl extends PrivateKeyImpl implements DSAPrivateKey {
+
+    /**
+     * @serial
+     */
+    private static final long serialVersionUID = -4716227614104950081L;
+
+    private BigInteger x;
+
+    private DSAParams params;
+
+    /**
+     * Creates object from DSAPrivateKeySpec.
+     *
+     * @param keySpec - a DSAPrivateKeySpec object
+     */
+    public DSAPrivateKeyImpl(DSAPrivateKeySpec keySpec) {
+
+        super("DSA"); //$NON-NLS-1$
+
+        PrivateKeyInfo pki;
+
+        BigInteger g = keySpec.getG();
+        BigInteger p = keySpec.getP();
+        BigInteger q = keySpec.getQ();
+
+        ThreeIntegerSequence threeInts = new ThreeIntegerSequence(p
+                .toByteArray(), q.toByteArray(), g.toByteArray());
+
+        AlgorithmIdentifier ai = new AlgorithmIdentifier(AlgNameMapper
+                .map2OID("DSA"), //$NON-NLS-1$
+                threeInts.getEncoded());
+        x = keySpec.getX();
+
+        pki = new PrivateKeyInfo(0, ai, ASN1Integer.getInstance().encode(
+                x.toByteArray()), null);
+
+        setEncoding(pki.getEncoded());
+
+        params = new DSAParameterSpec(p, q, g);
+    }
+
+    /**
+     * Creates object from PKCS8EncodedKeySpec.
+     *
+     * @param keySpec - a XPKCS8EncodedKeySpec object
+     *
+     * @throws InvalidKeySpecException - if key data cannot be obtain from encoded format
+     */
+    public DSAPrivateKeyImpl(PKCS8EncodedKeySpec keySpec)
+            throws InvalidKeySpecException {
+
+        super("DSA"); //$NON-NLS-1$
+
+        AlgorithmIdentifier ai;
+        ThreeIntegerSequence threeInts = null;
+
+        String alg, algName;
+
+        byte encoding[] = keySpec.getEncoded();
+
+        PrivateKeyInfo privateKeyInfo = null;
+
+        try {
+            privateKeyInfo = (PrivateKeyInfo) PrivateKeyInfo.ASN1
+                    .decode(encoding);
+        } catch (IOException e) {
+            throw new InvalidKeySpecException(Messages.getString(
+                    "security.19A", e)); //$NON-NLS-1$
+        }
+
+        try {
+            x = new BigInteger((byte[]) ASN1Integer.getInstance().decode(
+                    privateKeyInfo.getPrivateKey()));
+        } catch (IOException e) {
+            throw new InvalidKeySpecException(Messages.getString(
+                    "security.19B", e)); //$NON-NLS-1$
+        }
+
+        ai = privateKeyInfo.getAlgorithmIdentifier();
+        try {
+            threeInts = (ThreeIntegerSequence) ThreeIntegerSequence.ASN1
+                    .decode(ai.getParameters());
+        } catch (IOException e) {
+            throw new InvalidKeySpecException(Messages.getString(
+                    "security.19B", e)); //$NON-NLS-1$
+        }
+        params = new DSAParameterSpec(new BigInteger(threeInts.p),
+                new BigInteger(threeInts.q), new BigInteger(threeInts.g));
+
+        setEncoding(encoding);
+
+        /* 
+         * the following code implements RI behavior
+         */
+        alg = ai.getAlgorithm();
+        algName = AlgNameMapper.map2AlgName(alg);
+        setAlgorithm(algName == null ? alg : algName);
+    }
+
+    public BigInteger getX() {
+        return x;
+    }
+
+    public DSAParams getParams() {
+        return params;
+    }
+
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/DSAPublicKeyImpl.java b/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/DSAPublicKeyImpl.java
new file mode 100644
index 0000000..bd1efdd
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/DSAPublicKeyImpl.java
@@ -0,0 +1,180 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+ /*
+  * TODO
+  * 1. The class extends the PublicKeyImpl class in "org.apache.harmony.security" package.
+  *
+  * 2. The class uses methods in the auxiliary non-public "ThreeIntegerSequence" class 
+  *    defined along with the "DSAPrivateKeyImpl" class.
+  *
+  * 3. See a compatibility with RI comments
+  *    in the below "DSAPublicKeyImpl(X509EncodedKeySpec keySpec)" constructor.
+  */
+
+package org.apache.harmony.security.provider.crypto;
+
+import java.io.IOException;
+
+import java.math.BigInteger;
+
+import java.security.interfaces.DSAPublicKey;
+import java.security.interfaces.DSAParams;
+
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import org.apache.harmony.security.utils.AlgNameMapper;
+import org.apache.harmony.security.x509.AlgorithmIdentifier;
+import org.apache.harmony.security.x509.SubjectPublicKeyInfo;
+
+import org.apache.harmony.security.asn1.ASN1Integer;
+//import org.apache.harmony.security.asn1.ASN1Sequence;
+//import org.apache.harmony.security.asn1.ASN1Type;
+//import org.apache.harmony.security.asn1.BerInputStream;
+//import org.apache.harmony.security.asn1.ASN1BitString;
+//import org.apache.harmony.security.asn1.BitString;
+//import org.apache.harmony.security.asn1.ASN1OctetString;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+import org.apache.harmony.security.PublicKeyImpl;
+
+/**
+ * The class provides DSAPublicKey functionality by extending a class implementing PublicKey
+ * and implementing methods defined in both interfaces, DSAKey and DSAPublicKey
+ */
+public class DSAPublicKeyImpl extends PublicKeyImpl implements DSAPublicKey {
+
+    /**
+     * @serial
+     */
+    private static final long serialVersionUID = -2279672131310978336L;
+
+    private BigInteger y;
+
+    private DSAParams params;
+
+    /**
+     * Creates object from DSAPublicKeySpec.
+     *
+     * @param keySpec - a DSAPublicKeySpec object
+     */
+    public DSAPublicKeyImpl(DSAPublicKeySpec keySpec) {
+
+        super("DSA"); //$NON-NLS-1$
+
+        SubjectPublicKeyInfo spki;
+
+        BigInteger p = keySpec.getP();
+        BigInteger q = keySpec.getQ();
+        BigInteger g = keySpec.getG();
+
+        ThreeIntegerSequence threeInts = new ThreeIntegerSequence(p
+                .toByteArray(), q.toByteArray(), g.toByteArray());
+
+        AlgorithmIdentifier ai = new AlgorithmIdentifier(AlgNameMapper
+                .map2OID("DSA"), //$NON-NLS-1$
+                threeInts.getEncoded());
+
+        y = keySpec.getY();
+
+        spki = new SubjectPublicKeyInfo(ai, ASN1Integer.getInstance().encode(
+                y.toByteArray()));
+        setEncoding(spki.getEncoded());
+
+        params = (DSAParams) (new DSAParameterSpec(p, q, g));
+    }
+
+    /**
+     * Creates object from X509EncodedKeySpec.
+     *
+     * @param keySpec - a X509EncodedKeySpec object
+     *
+     * @throws InvalidKeySpecException - if key data cannot be obtain from encoded format
+     */
+    public DSAPublicKeyImpl(X509EncodedKeySpec keySpec)
+            throws InvalidKeySpecException {
+
+        super("DSA"); //$NON-NLS-1$
+
+        AlgorithmIdentifier ai;
+        ThreeIntegerSequence threeInts = null;
+
+        SubjectPublicKeyInfo subjectPublicKeyInfo = null;
+
+        byte encoding[] = keySpec.getEncoded();
+
+        String alg, algName;
+
+        try {
+            subjectPublicKeyInfo = (SubjectPublicKeyInfo) SubjectPublicKeyInfo.ASN1
+                    .decode(encoding);
+        } catch (IOException e) {
+            throw new InvalidKeySpecException(Messages.getString(
+                    "security.19A", e)); //$NON-NLS-1$
+        }
+
+        try {
+            y = new BigInteger((byte[]) ASN1Integer.getInstance().decode(
+                    subjectPublicKeyInfo.getSubjectPublicKey()));
+        } catch (IOException e) {
+            throw new InvalidKeySpecException(Messages.getString(
+                    "security.19B", e)); //$NON-NLS-1$
+        }
+
+        ai = subjectPublicKeyInfo.getAlgorithmIdentifier();
+
+        try {
+            threeInts = (ThreeIntegerSequence) ThreeIntegerSequence.ASN1
+                    .decode(ai.getParameters());
+        } catch (IOException e) {
+            throw new InvalidKeySpecException(Messages.getString(
+                    "security.19B", e)); //$NON-NLS-1$
+        }
+        params = (DSAParams) (new DSAParameterSpec(new BigInteger(threeInts.p),
+                new BigInteger(threeInts.q), new BigInteger(threeInts.g)));
+
+        setEncoding(encoding);
+
+        /* 
+         * the following code implements RI behavior
+         */
+        alg = ai.getAlgorithm();
+        algName = AlgNameMapper.map2AlgName(alg);
+        setAlgorithm(algName == null ? alg : algName);
+    }
+
+    /**
+     * @return 
+     *      a value of a public key (y).
+     */
+    public BigInteger getY() {
+        return y;
+    }
+
+    /**
+     * @return  
+     *     DSA key parameters (p, q, g).
+     */
+    public DSAParams getParams() {
+        return params;
+    }
+
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/RandomBitsSupplier.java b/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/RandomBitsSupplier.java
new file mode 100644
index 0000000..14db652
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/RandomBitsSupplier.java
@@ -0,0 +1,182 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+
+package org.apache.harmony.security.provider.crypto;
+
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.FileNotFoundException;
+
+import java.security.ProviderException;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+
+/**
+ *  The static class providing access on Linux platform
+ *  to system means for generating true random bits. <BR>
+ *
+ *  The source for true random bits is one of Linux's devices "/dev/urandom/" or
+ *  "/dev/random" depends on which one is available; if both the first is used. <BR>
+ *
+ *  If no device available the service is not available,
+ *  that is, provider shouldn't register the algorithm. <BR>
+ */
+
+
+public class RandomBitsSupplier implements SHA1_Data {
+
+
+    /**
+     *  BufferedInputStream to read from device
+     */
+    // BEGIN android-changed
+    // Using a BufferedInputStream leads to problems
+    // on Android in rare cases, since the
+    // BufferedInputStream's available() issues an
+    // iotcl(), and the pseudo device doesn't seem
+    // to like that. Since we're reading bigger
+    // chunks and not single bytes, the FileInputStream
+    // shouldn't be slower, so we use that. Same might
+    // apply to other Linux platforms.
+    private static FileInputStream bis = null;
+    // END android-changed 
+
+    /**
+     * File to connect to device
+     */
+    private static File randomFile = null;
+
+    /**
+     * value of field is "true" only if a device is available
+     */
+    private static boolean serviceAvailable;
+
+
+    static {
+        AccessController.doPrivileged(
+            new java.security.PrivilegedAction() {
+                public Object run() {
+
+                    for ( int i = 0 ; i < DEVICE_NAMES.length ; i++ ) {
+                        File file = new File(DEVICE_NAMES[i]);
+
+                        try {
+                            if ( file.canRead() ) {
+                                // BEGIN android-modified
+                                bis = new FileInputStream(file);
+                                // END android-modified
+                                randomFile = file;
+                                return null;
+                            }
+                        } catch (FileNotFoundException e) {
+                        }
+                    }
+                    return null;
+                }
+            }
+        );
+        serviceAvailable = (bis != null);
+    }
+
+
+    /**
+     * The method is called by provider to determine if a device is available.
+     */
+    static boolean isServiceAvailable() {
+        return serviceAvailable;
+    }
+
+
+    /**
+     * On the Linux platform with "random" devices available,
+     * the method reads random bytes from the device.  <BR>
+     *
+     * In case of any runtime failure ProviderException gets thrown.
+     */
+    private static synchronized byte[] getLinuxRandomBits(int numBytes) {
+
+        byte[] bytes = new byte[numBytes];
+
+        int total = 0;
+        int bytesRead;
+        int offset = 0;
+        try {
+            for ( ; ; ) {
+
+                bytesRead = bis.read(bytes, offset, numBytes-total);
+
+
+                // the below case should not occur because /dev/random or /dev/urandom is a special file
+                // hence, if it is happened there is some internal problem
+                //
+                if ( bytesRead == -1 ) {
+                    throw new ProviderException(
+                        Messages.getString("security.193") ); //$NON-NLS-1$
+                }
+
+                total  += bytesRead;
+                offset += bytesRead;
+
+                if ( total >= numBytes ) {
+                    break;
+                }          
+            }
+        } catch (IOException e) {
+
+            // actually there should be no IOException because device is a special file;
+            // hence, there is either some internal problem or, for instance,
+            // device was removed in runtime, or something else
+            //
+            throw new ProviderException(
+                Messages.getString("security.194"), e ); //$NON-NLS-1$
+        }
+        return bytes; 
+    }
+
+
+    /**
+     * The method returns byte array of requested length provided service is available.
+     * ProviderException gets thrown otherwise.
+     *
+     * @param
+     *       numBytes - length of bytes requested
+     * @return
+     *       byte array
+     * @throws
+     *       InvalidArgumentException - if numBytes <= 0
+     */
+    public static byte[] getRandomBits(int numBytes) {
+
+        if ( numBytes <= 0 ) {
+            throw new IllegalArgumentException(Messages.getString("security.195", numBytes)); //$NON-NLS-1$
+        }
+
+        if ( !serviceAvailable ) {
+            throw new ProviderException(
+                Messages.getString("security.196")); //$NON-NLS-1$
+        }
+
+        return getLinuxRandomBits(numBytes);
+    }
+
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/SHA1Impl.java b/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/SHA1Impl.java
new file mode 100644
index 0000000..71c0384
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/SHA1Impl.java
@@ -0,0 +1,247 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+/**
+* @author Yuri A. Kropachev
+* @version $Revision$
+*/
+
+
+package org.apache.harmony.security.provider.crypto;
+
+
+/**
+ * This class contains methods providing SHA-1 functionality to use in classes. <BR>
+ * The methods support the algorithm described in "SECURE HASH STANDARD", FIPS PUB 180-2, <BR>
+ * "http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf"      <BR>
+ * <BR>
+ * The class contains two package level access methods, -
+ * "void updateHash(int[], byte[], int, int)" and "void computeHash(int[])", -
+ * performing the following operations. <BR>
+ * <BR>
+ * The "updateHash(..)" method appends new bytes to existing ones 
+ * within limit of a frame of 64 bytes (16 words).
+ * Once a length of accumulated bytes reaches the limit
+ * the "computeHash(int[])" method is invoked on the frame to compute updated hash,
+ * and the number of bytes in the frame is set to 0.
+ * Thus, after appending all bytes, the frame contain only those bytes
+ * that were not used in computing final hash value yet. <BR>
+ * <BR>
+ * The "computeHash(..)" method generates a 160 bit hash value using 
+ * a 512 bit message stored in first 16 words of int[] array argument and
+ * current hash value stored in five words, beginning HASH_OFFSET, of the array argument.
+ * Computation is done according to SHA-1 algorithm. <BR>
+ * <BR>
+ * The resulting hash value replaces the previous hash value in the array;
+ * original bits of the message are not preserved.
+ */
+
+
+public class SHA1Impl implements SHA1_Data {
+
+
+    /**
+     * The method generates a 160 bit hash value using 
+     * a 512 bit message stored in first 16 words of int[] array argument and
+     * current hash value stored in five words, beginning OFFSET+1, of the array argument.
+     * Computation is done according to SHA-1 algorithm.
+     *
+     * The resulting hash value replaces the previous hash value in the array;
+     * original bits of the message are not preserved.
+     *
+     * No checks on argument supplied, that is,
+     * a calling method is responsible for such checks.
+     * In case of incorrect array passed to the method
+     * either NPE or IndexOutOfBoundException gets thrown by JVM.
+     *
+     * @params 
+     *        arrW - integer array; arrW.length >= (BYTES_OFFSET+6); <BR>
+     *               only first (BYTES_OFFSET+6) words are used
+     */
+    static void computeHash(int arrW[]) {
+
+        int  a = arrW[HASH_OFFSET   ];
+        int  b = arrW[HASH_OFFSET +1];
+        int  c = arrW[HASH_OFFSET +2];
+        int  d = arrW[HASH_OFFSET +3];
+        int  e = arrW[HASH_OFFSET +4];
+
+        int temp;
+
+        // In this implementation the "d. For t = 0 to 79 do" loop
+        // is split into four loops. The following constants:
+        //     K = 5A827999   0 <= t <= 19
+        //     K = 6ED9EBA1  20 <= t <= 39
+        //     K = 8F1BBCDC  40 <= t <= 59
+        //     K = CA62C1D6  60 <= t <= 79
+        // are hex literals in the loops.
+
+        for ( int t = 16; t < 80 ; t++ ) {
+
+            temp  = arrW[t-3] ^ arrW[t-8] ^ arrW[t-14] ^ arrW[t-16];
+            arrW[t] = ( temp<<1 ) | ( temp>>>31 );
+        }
+
+        for ( int t = 0 ; t < 20 ; t++ ) {
+
+            temp = ( ( a<<5 ) | ( a>>>27 )   ) + 
+                   ( ( b & c) | ((~b) & d)   ) + 
+                   ( e + arrW[t] + 0x5A827999 ) ;
+            e = d;
+            d = c;
+            c = ( b<<30 ) | ( b>>>2 ) ;
+            b = a;
+            a = temp;
+        }
+        for ( int t = 20 ; t < 40 ; t++ ) {
+
+            temp = ((( a<<5 ) | ( a>>>27 ))) + (b ^ c ^ d) + (e + arrW[t] + 0x6ED9EBA1) ;
+            e = d;
+            d = c;
+            c = ( b<<30 ) | ( b>>>2 ) ;
+            b = a;
+            a = temp;
+        }
+        for ( int t = 40 ; t < 60 ; t++ ) {
+
+            temp = (( a<<5 ) | ( a>>>27 )) + ((b & c) | (b & d) | (c & d)) +
+                                                             (e + arrW[t] + 0x8F1BBCDC) ;
+            e = d;
+            d = c;
+            c = ( b<<30 ) | ( b>>>2 ) ;
+            b = a;
+            a = temp;
+        }
+        for ( int t = 60 ; t < 80 ; t++ ) {
+
+            temp = ((( a<<5 ) | ( a>>>27 ))) + (b ^ c ^ d) + (e + arrW[t] + 0xCA62C1D6) ;
+            e = d;
+            d = c;
+            c = ( b<<30 ) | ( b>>>2 ) ;
+            b = a;
+            a = temp;
+        }
+
+        arrW[HASH_OFFSET   ] += a;
+        arrW[HASH_OFFSET +1] += b;
+        arrW[HASH_OFFSET +2] += c;
+        arrW[HASH_OFFSET +3] += d;
+        arrW[HASH_OFFSET +4] += e;
+    }
+
+    /**
+     * The method appends new bytes to existing ones 
+     * within limit of a frame of 64 bytes (16 words).
+     *
+     * Once a length of accumulated bytes reaches the limit
+     * the "computeHash(int[])" method is invoked on the array to compute updated hash,
+     * and the number of bytes in the frame is set to 0.
+     * Thus, after appending all bytes, the array contain only those bytes
+     * that were not used in computing final hash value yet.
+     *
+     * No checks on arguments passed to the method, that is, 
+     * a calling method is responsible for such checks. 
+     *
+     * @params
+     *        intArray  - int array containing bytes to which to append;
+     *                    intArray.length >= (BYTES_OFFSET+6)
+     * @params
+     *        byteInput - array of bytes to use for the update
+     * @params
+     *        from      - the offset to start in the "byteInput" array
+     * @params
+     *        to        - a number of the last byte in the input array to use, 
+     *                that is, for first byte "to"==0, for last byte "to"==input.length-1
+     */
+    static void updateHash(int intArray[], byte byteInput[], int fromByte, int toByte) {
+
+        // As intArray contains a packed bytes
+        // the buffer's index is in the intArray[BYTES_OFFSET] element
+
+        int index = intArray[BYTES_OFFSET];
+        int i = fromByte;
+        int maxWord;
+        int nBytes;
+
+        int wordIndex = index >>2;
+        int byteIndex = index & 0x03;
+
+        intArray[BYTES_OFFSET] = ( index + toByte - fromByte + 1 ) & 077 ;
+
+        // In general case there are 3 stages :
+        // - appending bytes to non-full word,
+        // - writing 4 bytes into empty words,
+        // - writing less than 4 bytes in last word
+
+        if ( byteIndex != 0 ) {       // appending bytes in non-full word (as if)
+
+            for ( ; ( i <= toByte ) && ( byteIndex < 4 ) ; i++ ) {
+                intArray[wordIndex] |= ( byteInput[i] & 0xFF ) << ((3 - byteIndex)<<3) ;
+                byteIndex++;
+            }
+            if ( byteIndex == 4 ) {
+                wordIndex++;
+                if ( wordIndex == 16 ) {          // intArray is full, computing hash
+
+                    computeHash(intArray);
+                    wordIndex = 0;
+                }
+            }
+            if ( i > toByte ) {                 // all input bytes appended
+                return ;
+            }
+        }
+
+        // writing full words
+
+        maxWord = (toByte - i + 1) >> 2;           // # of remaining full words, may be "0"
+        for ( int k = 0; k < maxWord ; k++ ) {
+
+            intArray[wordIndex] = ( ((int) byteInput[i   ] & 0xFF) <<24 ) |
+                                  ( ((int) byteInput[i +1] & 0xFF) <<16 ) |
+                                  ( ((int) byteInput[i +2] & 0xFF) <<8  ) |
+                                  ( ((int) byteInput[i +3] & 0xFF)      )  ;
+            i += 4;
+            wordIndex++;
+
+            if ( wordIndex < 16 ) {     // buffer is not full yet
+                continue;
+            }
+            computeHash(intArray);      // buffer is full, computing hash
+            wordIndex = 0;
+        }
+
+        // writing last incomplete word
+        // after writing free byte positions are set to "0"s
+
+        nBytes = toByte - i +1;
+        if ( nBytes != 0 ) {
+
+            int w =  ((int) byteInput[i] & 0xFF) <<24 ;
+
+            if ( nBytes != 1 ) {
+                w |= ((int) byteInput[i +1] & 0xFF) <<16 ;
+                if ( nBytes != 2) {
+                    w |= ((int) byteInput[i +2] & 0xFF) <<8 ;
+                }
+            }
+            intArray[wordIndex] = w;
+        }
+
+        return ;
+    }
+
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl.java b/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl.java
new file mode 100644
index 0000000..cd926d8
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl.java
@@ -0,0 +1,537 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+
+package org.apache.harmony.security.provider.crypto;
+
+import java.security.InvalidParameterException;
+import java.security.SecureRandomSpi;
+
+import org.apache.harmony.security.internal.nls.Messages;
+import org.apache.harmony.security.provider.crypto.RandomBitsSupplier;
+import org.apache.harmony.security.provider.crypto.SHA1Impl;
+
+import java.io.Serializable;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
+
+/**
+ * This class extends the SecureRandomSpi class implementing all its abstract methods. <BR>
+ * <BR>
+ * To generate pseudo-random bits, the implementation uses technique described in
+ * the "Random Number Generator (RNG) algorithms" section, Appendix A,
+ * JavaTM Cryptography Architecture, API Specification&Reference <BR>
+ * <BR>
+ * The class implements the Serializable interface.
+ */
+
+public class SHA1PRNG_SecureRandomImpl extends SecureRandomSpi implements
+        Serializable, SHA1_Data {
+
+    private static final long serialVersionUID = 283736797212159675L;
+
+    // constants to use in expressions operating on bytes in int and long variables:
+    // END_FLAGS - final bytes in words to append to message; 
+    //             see "ch.5.1 Padding the Message, FIPS 180-2"
+    // RIGHT1    - shifts to right for left half of long
+    // RIGHT2    - shifts to right for right half of long
+    // LEFT      - shifts to left for bytes
+    // MASK      - mask to select counter's bytes after shift to right
+
+    private static final int[] END_FLAGS = { 0x80000000, 0x800000, 0x8000, 0x80 };
+
+    private static final int[] RIGHT1 = { 0, 40, 48, 56 };
+
+    private static final int[] RIGHT2 = { 0, 8, 16, 24 };
+
+    private static final int[] LEFT = { 0, 24, 16, 8 };
+
+    private static final int[] MASK = { 0xFFFFFFFF, 0x00FFFFFF, 0x0000FFFF,
+            0x000000FF };
+
+    // HASHBYTES_TO_USE defines # of bytes returned by "computeHash(byte[])"
+    // to use to form byte array returning by the "nextBytes(byte[])" method
+    // Note, that this implementation uses more bytes than it is defined
+    // in the above specification.
+    private static final int HASHBYTES_TO_USE = 20;
+
+    // value of 16 defined in the "SECURE HASH STANDARD", FIPS PUB 180-2
+    private static final int FRAME_LENGTH = 16;
+
+    // miscellaneous constants defined in this implementation:
+    // COUNTER_BASE - initial value to set to "counter" before computing "nextBytes(..)";
+    //                note, that the exact value is not defined in STANDARD
+    // HASHCOPY_OFFSET   - offset for copy of current hash in "copies" array
+    // EXTRAFRAME_OFFSET - offset for extra frame in "copies" array;
+    //                     as the extra frame follows the current hash frame, 
+    //                     EXTRAFRAME_OFFSET is equal to length of current hash frame
+    // FRAME_OFFSET      - offset for frame in "copies" array
+    // MAX_BYTES - maximum # of seed bytes processing which doesn't require extra frame
+    //             see (1) comments on usage of "seed" array below and
+    //             (2) comments in "engineNextBytes(byte[])" method
+    //
+    // UNDEFINED  - three states of engine; initially its state is "UNDEFINED"
+    // SET_SEED     call to "engineSetSeed"  sets up "SET_SEED" state,
+    // NEXT_BYTES   call to "engineNextByte" sets up "NEXT_BYTES" state
+
+    private static final int COUNTER_BASE = 0;
+
+    private static final int HASHCOPY_OFFSET = 0;
+
+    private static final int EXTRAFRAME_OFFSET = 5;
+
+    private static final int FRAME_OFFSET = 21;
+
+    private static final int MAX_BYTES = 48;
+
+    private static final int UNDEFINED = 0;
+
+    private static final int SET_SEED = 1;
+
+    private static final int NEXT_BYTES = 2;
+
+    private static SHA1PRNG_SecureRandomImpl myRandom;
+
+    // Structure of "seed" array: 
+    // -  0-79 - words for computing hash
+    // - 80    - unused 
+    // - 81    - # of seed bytes in current seed frame
+    // - 82-86 - 5 words, current seed hash
+    private transient int seed[];
+
+    // total length of seed bytes, including all processed
+    private transient long seedLength;
+
+    // Structure of "copies" array
+    // -  0-4  - 5 words, copy of current seed hash
+    // -  5-20 - extra 16 words frame; 
+    //           is used if final padding exceeds 512-bit length 
+    // - 21-36 - 16 word frame to store a copy of remaining bytes
+    private transient int copies[];
+
+    // ready "next" bytes; needed because words are returned
+    private transient byte nextBytes[];
+
+    // index of used bytes in "nextBytes" array
+    private transient int nextBIndex;
+
+    // variable required according to "SECURE HASH STANDARD"
+    private transient long counter;
+
+    // contains int value corresponding to engine's current state 
+    private transient int state;
+
+    // The "seed" array is used to compute both "current seed hash" and "next bytes".
+    //
+    // As the "SHA1" algorithm computes a hash of entire seed by splitting it into
+    // a number of the 512-bit length frames (512 bits = 64 bytes = 16 words),
+    // "current seed hash" is a hash (5 words, 20 bytes) for all previous full frames;
+    // remaining bytes are stored in the 0-15 word frame of the "seed" array.
+    //
+    // As for calculating "next bytes",
+    // both remaining bytes and "current seed hash" are used,
+    // to preserve the latter for following "setSeed(..)" commands,
+    // the following technique is used:
+    // - upon getting "nextBytes(byte[])" invoked, single or first in row,
+    //   which requires computing new hash, that is, 
+    //   there is no more bytes remaining from previous "next bytes" computation,
+    //   remaining bytes are copied into the 21-36 word frame of the "copies" array;
+    // - upon getting "setSeed(byte[])" invoked, single or first in row,
+    //   remaining bytes are copied back. 
+
+    /**
+     *  Creates object and sets implementation variables to their initial values
+     */
+    public SHA1PRNG_SecureRandomImpl() {
+
+        seed = new int[HASH_OFFSET + EXTRAFRAME_OFFSET];
+        seed[HASH_OFFSET] = H0;
+        seed[HASH_OFFSET + 1] = H1;
+        seed[HASH_OFFSET + 2] = H2;
+        seed[HASH_OFFSET + 3] = H3;
+        seed[HASH_OFFSET + 4] = H4;
+
+        seedLength = 0;
+        copies = new int[2 * FRAME_LENGTH + EXTRAFRAME_OFFSET];
+        nextBytes = new byte[DIGEST_LENGTH];
+        nextBIndex = HASHBYTES_TO_USE;
+        counter = COUNTER_BASE;
+        state = UNDEFINED;
+    }
+
+    /*
+     * The method invokes the SHA1Impl's "updateHash(..)" method
+     * to update current seed frame and
+     * to compute new intermediate hash value if the frame is full.
+     * 
+     * After that it computes a length of whole seed.
+     */
+    private void updateSeed(byte[] bytes) {
+
+        // on call:   "seed" contains current bytes and current hash;
+        // on return: "seed" contains new current bytes and possibly new current hash
+        //            if after adding, seed bytes overfill its buffer
+        SHA1Impl.updateHash(seed, bytes, 0, bytes.length - 1);
+
+        seedLength += bytes.length;
+    }
+
+    /**
+     * Changes current seed by supplementing a seed argument to the current seed,
+     * if this already set;
+     * the argument is used as first seed otherwise. <BR>
+     *
+     * The method overrides "engineSetSeed(byte[])" in class SecureRandomSpi.
+     *
+     * @param
+     *       seed - byte array
+     * @throws
+     *       NullPointerException - if null is passed to the "seed" argument
+     */
+    protected void engineSetSeed(byte[] seed) {
+
+        if (seed == null) {
+            throw new NullPointerException(
+                    Messages.getString("security.83", "seed")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        if (state == NEXT_BYTES) { // first setSeed after NextBytes; restoring hash
+            System.arraycopy(copies, HASHCOPY_OFFSET, this.seed, HASH_OFFSET,
+                    EXTRAFRAME_OFFSET);
+        }
+        state = SET_SEED;
+
+        if (seed.length != 0) {
+            updateSeed(seed);
+        }
+    }
+
+    /**
+     * Returns a required number of random bytes. <BR>
+     *
+     * The method overrides "engineGenerateSeed (int)" in class SecureRandomSpi. <BR>
+     *
+     * @param
+     *       numBytes - number of bytes to return; should be >= 0.
+     * @return
+     *       byte array containing bits in order from left to right
+     * @throws
+     *       InvalidParameterException - if numBytes < 0
+     */
+    protected byte[] engineGenerateSeed(int numBytes) {
+
+        byte[] myBytes; // byte[] for bytes returned by "nextBytes()"
+
+        if (numBytes < 0) {
+            throw new NegativeArraySizeException(Messages.getString("security.171", numBytes)); //$NON-NLS-1$
+        }
+        if (numBytes == 0) {
+            return new byte[0];
+        }
+
+        if (myRandom == null) {
+            myRandom = new SHA1PRNG_SecureRandomImpl();
+            myRandom.engineSetSeed(RandomBitsSupplier
+                    .getRandomBits(DIGEST_LENGTH));
+        }
+
+        myBytes = new byte[numBytes];
+        myRandom.engineNextBytes(myBytes);
+
+        return myBytes;
+    }
+
+    /**
+     * Writes random bytes into an array supplied.
+     * Bits in a byte are from left to right. <BR>
+     *
+     * To generate random bytes, the "expansion of source bits" method is used,
+     * that is,
+     * the current seed with a 64-bit counter appended is used to compute new bits.
+     * The counter is incremented by 1 for each 20-byte output. <BR>
+     *
+     * The method overrides engineNextBytes in class SecureRandomSpi.
+     *
+     * @param
+     *       bytes - byte array to be filled in with bytes
+     * @throws
+     *       NullPointerException - if null is passed to the "bytes" argument
+     */
+    protected void engineNextBytes(byte[] bytes) {
+
+        int i, n;
+
+        long bits; // number of bits required by Secure Hash Standard
+        int nextByteToReturn; // index of ready bytes in "bytes" array
+        int lastWord; // index of last word in frame containing bytes
+        final int extrabytes = 7;// # of bytes to add in order to computer # of 8 byte words
+
+        if (bytes == null) {
+            throw new NullPointerException(
+                    Messages.getString("security.83", "bytes")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        lastWord = seed[BYTES_OFFSET] == 0 ? 0
+                : (seed[BYTES_OFFSET] + extrabytes) >> 3 - 1;
+
+        if (state == UNDEFINED) {
+
+            // no seed supplied by user, hence it is generated thus randomizing internal state
+            updateSeed(RandomBitsSupplier.getRandomBits(DIGEST_LENGTH));
+            nextBIndex = HASHBYTES_TO_USE;
+
+        } else if (state == SET_SEED) {
+
+            System.arraycopy(seed, HASH_OFFSET, copies, HASHCOPY_OFFSET,
+                    EXTRAFRAME_OFFSET);
+
+            // possible cases for 64-byte frame:
+            //
+            // seed bytes < 48      - remaining bytes are enough for all, 8 counter bytes, 
+            //                        0x80, and 8 seedLength bytes; no extra frame required
+            // 48 < seed bytes < 56 - remaining 9 bytes are for 0x80 and 8 counter bytes
+            //                        extra frame contains only seedLength value at the end
+            // seed bytes > 55      - extra frame contains both counter's bytes
+            //                        at the beginning and seedLength value at the end;
+            //                        note, that beginning extra bytes are not more than 8,
+            //                        that is, only 2 extra words may be used
+
+            // no need to set to "0" 3 words after "lastWord" and  
+            // more than two words behind frame 
+            for (i = lastWord + 3; i < FRAME_LENGTH + 2; i++) {
+                seed[i] = 0;
+            }
+
+            bits = seedLength << 3 + 64; // transforming # of bytes into # of bits
+
+            // putting # of bits into two last words (14,15) of 16 word frame in 
+            // seed or copies array depending on total length after padding
+            if (seed[BYTES_OFFSET] < MAX_BYTES) {
+                seed[14] = (int) (bits >>> 32);
+                seed[15] = (int) (bits & 0xFFFFFFFF);
+            } else {
+                copies[EXTRAFRAME_OFFSET + 14] = (int) (bits >>> 32);
+                copies[EXTRAFRAME_OFFSET + 15] = (int) (bits & 0xFFFFFFFF);
+            }
+
+            nextBIndex = HASHBYTES_TO_USE; // skipping remaining random bits
+        }
+        state = NEXT_BYTES;
+
+        if (bytes.length == 0) {
+            return;
+        }
+
+        nextByteToReturn = 0;
+
+        // possibly not all of HASHBYTES_TO_USE bytes were used previous time 
+        n = (HASHBYTES_TO_USE - nextBIndex) < (bytes.length - nextByteToReturn) ? HASHBYTES_TO_USE
+                - nextBIndex
+                : bytes.length - nextByteToReturn;
+        if (n > 0) {
+            System.arraycopy(nextBytes, nextBIndex, bytes, nextByteToReturn, n);
+            nextBIndex += n;
+            nextByteToReturn += n;
+        }
+
+        if (nextByteToReturn >= bytes.length) {
+            return; // return because "bytes[]" are filled in
+        }
+
+        n = seed[BYTES_OFFSET] & 0x03;
+        for (;;) {
+            if (n == 0) {
+
+                seed[lastWord] = (int) (counter >>> 32);
+                seed[lastWord + 1] = (int) (counter & 0xFFFFFFFF);
+                seed[lastWord + 2] = END_FLAGS[0];
+
+            } else {
+
+                seed[lastWord] |= (int) ((counter >>> RIGHT1[n]) & MASK[n]);
+                seed[lastWord + 1] = (int) ((counter >>> RIGHT2[n]) & 0xFFFFFFFF);
+                seed[lastWord + 2] = (int) ((counter << LEFT[n]) | END_FLAGS[n]);
+            }
+            if (seed[BYTES_OFFSET] > MAX_BYTES) {
+                copies[EXTRAFRAME_OFFSET] = seed[FRAME_LENGTH];
+                copies[EXTRAFRAME_OFFSET + 1] = seed[FRAME_LENGTH + 1];
+            }
+
+            SHA1Impl.computeHash(seed);
+
+            if (seed[BYTES_OFFSET] > MAX_BYTES) {
+
+                System.arraycopy(seed, 0, copies, FRAME_OFFSET, FRAME_LENGTH);
+                System.arraycopy(copies, EXTRAFRAME_OFFSET, seed, 0,
+                        FRAME_LENGTH);
+
+                SHA1Impl.computeHash(seed);
+                System.arraycopy(copies, FRAME_OFFSET, seed, 0, FRAME_LENGTH);
+            }
+            counter++;
+
+            int j = 0;
+            for (i = 0; i < EXTRAFRAME_OFFSET; i++) {
+                int k = seed[HASH_OFFSET + i];
+                nextBytes[j] = (byte) (k >>> 24); // getting first  byte from left
+                nextBytes[j + 1] = (byte) (k >>> 16); // getting second byte from left
+                nextBytes[j + 2] = (byte) (k >>> 8); // getting third  byte from left
+                nextBytes[j + 3] = (byte) (k); // getting fourth byte from left
+                j += 4;
+            }
+
+            nextBIndex = 0;
+            j = HASHBYTES_TO_USE < (bytes.length - nextByteToReturn) ? HASHBYTES_TO_USE
+                    : bytes.length - nextByteToReturn;
+
+            if (j > 0) {
+                System.arraycopy(nextBytes, 0, bytes, nextByteToReturn, j);
+                nextByteToReturn += j;
+                nextBIndex += j;
+            }
+
+            if (nextByteToReturn >= bytes.length) {
+                break;
+            }
+        }
+    }
+
+    private void writeObject(ObjectOutputStream oos) throws IOException {
+
+        int[] intData = null;
+
+        final int only_hash = EXTRAFRAME_OFFSET;
+        final int hashes_and_frame = EXTRAFRAME_OFFSET * 2 + FRAME_LENGTH;
+        final int hashes_and_frame_extra = EXTRAFRAME_OFFSET * 2 + FRAME_LENGTH
+                * 2;
+
+        oos.writeLong(seedLength);
+        oos.writeLong(counter);
+        oos.writeInt(state);
+        oos.writeInt(seed[BYTES_OFFSET]);
+
+        int nRemaining = (seed[BYTES_OFFSET] + 3) >> 2; // converting bytes in words
+        // result may be 0
+        if (state != NEXT_BYTES) {
+
+            // either the state is UNDEFINED or previous method was "setSeed(..)" 
+            // so in "seed[]" to serialize are remaining bytes (seed[0-nRemaining]) and
+            // current hash (seed[82-86])
+
+            intData = new int[only_hash + nRemaining];
+
+            System.arraycopy(seed, 0, intData, 0, nRemaining);
+            System.arraycopy(seed, HASH_OFFSET, intData, nRemaining,
+                    EXTRAFRAME_OFFSET);
+
+        } else {
+            // previous method was "nextBytes(..)"
+            // so, data to serialize are all the above (two first are in "copies" array)
+            // and current words in both frame and extra frame (as if)
+
+            int offset = 0;
+            if (seed[BYTES_OFFSET] < MAX_BYTES) { // no extra frame
+
+                intData = new int[hashes_and_frame + nRemaining];
+
+            } else { // extra frame is used
+
+                intData = new int[hashes_and_frame_extra + nRemaining];
+
+                intData[offset] = seed[FRAME_LENGTH];
+                intData[offset + 1] = seed[FRAME_LENGTH + 1];
+                intData[offset + 2] = seed[FRAME_LENGTH + 14];
+                intData[offset + 3] = seed[FRAME_LENGTH + 15];
+                offset += 4;
+            }
+
+            System.arraycopy(seed, 0, intData, offset, FRAME_LENGTH);
+            offset += FRAME_LENGTH;
+
+            System.arraycopy(copies, FRAME_LENGTH + EXTRAFRAME_OFFSET, intData,
+                    offset, nRemaining);
+            offset += nRemaining;
+
+            System.arraycopy(copies, 0, intData, offset, EXTRAFRAME_OFFSET);
+            offset += EXTRAFRAME_OFFSET;
+
+            System.arraycopy(seed, HASH_OFFSET, intData, offset,
+                    EXTRAFRAME_OFFSET);
+        }
+        for (int i = 0; i < intData.length; i++) {
+            oos.writeInt(intData[i]);
+        }
+
+        oos.writeInt(nextBIndex);
+        oos.write(nextBytes, nextBIndex, HASHBYTES_TO_USE - nextBIndex);
+    }
+
+    private void readObject(ObjectInputStream ois) throws IOException,
+            ClassNotFoundException {
+
+        seed = new int[HASH_OFFSET + EXTRAFRAME_OFFSET];
+        copies = new int[2 * FRAME_LENGTH + EXTRAFRAME_OFFSET];
+        nextBytes = new byte[DIGEST_LENGTH];
+
+        seedLength = ois.readLong();
+        counter = ois.readLong();
+        state = ois.readInt();
+        seed[BYTES_OFFSET] = ois.readInt();
+
+        int nRemaining = (seed[BYTES_OFFSET] + 3) >> 2; // converting bytes in words
+
+        if (state != NEXT_BYTES) {
+
+            for (int i = 0; i < nRemaining; i++) {
+                seed[i] = ois.readInt();
+            }
+            for (int i = 0; i < EXTRAFRAME_OFFSET; i++) {
+                seed[HASH_OFFSET + i] = ois.readInt();
+            }
+        } else {
+            if (seed[BYTES_OFFSET] >= MAX_BYTES) {
+
+                // reading next bytes in seed extra frame
+                seed[FRAME_LENGTH] = ois.readInt();
+                seed[FRAME_LENGTH + 1] = ois.readInt();
+                seed[FRAME_LENGTH + 14] = ois.readInt();
+                seed[FRAME_LENGTH + 15] = ois.readInt();
+            }
+            // reading next bytes in seed frame
+            for (int i = 0; i < FRAME_LENGTH; i++) {
+                seed[i] = ois.readInt();
+            }
+            // reading remaining seed bytes 
+            for (int i = 0; i < nRemaining; i++) {
+                copies[FRAME_LENGTH + EXTRAFRAME_OFFSET + i] = ois.readInt();
+            }
+            // reading copy of current hash
+            for (int i = 0; i < EXTRAFRAME_OFFSET; i++) {
+                copies[i] = ois.readInt();
+            }
+            // reading current hash
+            for (int i = 0; i < EXTRAFRAME_OFFSET; i++) {
+                seed[HASH_OFFSET + i] = ois.readInt();
+            }
+        }
+
+        nextBIndex = ois.readInt();
+        ois.read(nextBytes, nextBIndex, HASHBYTES_TO_USE - nextBIndex);
+    }
+
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/SHA1_Data.java b/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/SHA1_Data.java
new file mode 100644
index 0000000..6e9ecb8
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/SHA1_Data.java
@@ -0,0 +1,97 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+/**
+* @author Yuri A. Kropachev
+* @version $Revision$
+*/
+
+
+package org.apache.harmony.security.provider.crypto;
+
+
+/**
+ * This interface contains : <BR>
+ * - a set of constant values, H0-H4, defined in "SECURE HASH STANDARD", FIPS PUB 180-2 ;<BR>
+ * - implementation constant values to use in classes using SHA-1 algorithm.    <BR>
+ */
+
+
+public interface SHA1_Data {
+
+
+    /**
+     *  constant defined in "SECURE HASH STANDARD"
+     */
+    static final int H0 = 0x67452301;
+
+
+    /**
+     *  constant defined in "SECURE HASH STANDARD"
+     */
+    static final int H1 = 0xEFCDAB89;
+
+
+    /**
+     *  constant defined in "SECURE HASH STANDARD"
+     */
+    static final int H2 = 0x98BADCFE;
+
+
+    /**
+     *  constant defined in "SECURE HASH STANDARD"
+     */
+    static final int H3 = 0x10325476;
+
+
+    /**
+     *  constant defined in "SECURE HASH STANDARD"
+     */
+    static final int H4 = 0xC3D2E1F0;
+
+
+    /**
+     * offset in buffer to store number of bytes in 0-15 word frame
+     */
+    static final int BYTES_OFFSET = 81;
+
+
+    /**
+     * offset in buffer to store current hash value
+     */
+    static final int HASH_OFFSET = 82;
+
+
+    /**
+     * # of bytes in H0-H4 words; <BR>
+     * in this implementation # is set to 20 (in general # varies from 1 to 20)
+     */
+    static final int DIGEST_LENGTH = 20;
+
+
+    /**
+     *  name of native library to use on Windows platform
+     */
+    static final String LIBRARY_NAME = "hysecurity";  //$NON-NLS-1$
+
+
+    /**
+     *  names of random devices on Linux platform
+     */
+    // BEGIN android-changed: /dev/random seems to be empty on Android 
+    static final String DEVICE_NAMES[] = { "/dev/urandom" /*, "/dev/random" */ }; //$NON-NLS-1$ //$NON-NLS-2$
+    // END android-changed
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/SHA1_MessageDigestImpl.java b/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/SHA1_MessageDigestImpl.java
new file mode 100644
index 0000000..dd59514
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/SHA1_MessageDigestImpl.java
@@ -0,0 +1,325 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+
+package org.apache.harmony.security.provider.crypto;
+
+
+import java.security.MessageDigestSpi;
+import java.security.DigestException;
+
+import java.util.Arrays;
+
+import org.apache.harmony.security.internal.nls.Messages;
+import org.apache.harmony.security.provider.crypto.SHA1_Data;
+import org.apache.harmony.security.provider.crypto.SHA1Impl;
+
+
+/**
+ * This class extends the MessageDigestSpi class implementing all its abstract methods;
+ * it overrides the "Object clone()" and "int engineGetDigestLength()" methods. <BR>
+ * The class implements the Cloneable interface.
+ */
+
+
+public class SHA1_MessageDigestImpl extends MessageDigestSpi 
+                                    implements Cloneable, SHA1_Data {
+
+
+    private  int buffer[];       // buffer has the following structure:
+                                 // -  0-16 - frame for accumulating a message
+                                 // - 17-79 - for SHA1Impl methods
+                                 // - 80    - unused
+                                 // - 81    - to store length of the message
+                                 // - 82-86 - frame for current message digest
+
+    private byte oneByte[];      // one byte buffer needed to use in engineUpdate(byte)
+                                 // having buffer as private field is just optimization
+
+    private int messageLength;   // total length of bytes supplied by user
+
+
+    /**
+     *  The constructor creates needed buffers and sets the engine at initial state
+     */ 
+    public SHA1_MessageDigestImpl() {
+
+        // BYTES_OFFSET +6 is minimal length required by methods in SHA1Impl
+        buffer  = new int[BYTES_OFFSET +6];
+
+        oneByte = new byte[1];
+
+        engineReset();
+    }
+
+
+    /**
+     * The method performs final actions and invokes the "computeHash(int[])" method.
+     * In case if there is no enough words in current frame
+     * after processing its data, extra frame is prepared and 
+     * the "computeHash(int[])" method is invoked second time. <BR>
+     *
+     * After processing, the method resets engine's state
+     *
+     * @param
+     *       digest - byte array
+     * @param
+     *       offset - offset in digest
+     */
+    private void processDigest(byte[] digest, int offset) {
+
+        int i, j;         // implementation variables
+        int lastWord;     //
+
+        long nBits = messageLength <<3 ;  // length has to be calculated before padding
+
+        engineUpdate( (byte) 0x80 );      // beginning byte in padding
+
+        i = 0;                     // i contains number of beginning word for following loop
+
+        lastWord = (buffer[BYTES_OFFSET] + 3)>>2 ;  // computing of # of full words by shifting
+                                                    // # of bytes
+
+        // possible cases:
+        //
+        // - buffer[BYTES_OFFSET] == 0 - buffer frame is empty, 
+        //                         padding byte was 64th in previous frame
+        //                         current frame should contain only message's length
+        //
+        // - lastWord < 14 - two last, these are 14 & 15, words in 16 word frame are free;
+        //                   no extra frame needed
+        // - lastWord = 14 - only one last, namely 15-th, word in frame doesn't contain bytes;
+        //                   extra frame is needed
+        // - lastWord > 14 - last word in frame is not full; 
+        //                   extra frame is needed
+
+        if ( buffer[BYTES_OFFSET] != 0 ) {
+
+            if ( lastWord < 15 ) {
+                i = lastWord;
+            } else {
+                if ( lastWord == 15 ) {
+                    buffer[15] = 0;       // last word in frame is set to "0"
+                }
+                SHA1Impl.computeHash(buffer);
+                i = 0;
+            }
+        }
+        Arrays.fill(buffer, i, 14, 0);
+
+        buffer[14] = (int)( nBits >>>32 );
+        buffer[15] = (int)( nBits & 0xFFFFFFFF );
+        SHA1Impl.computeHash(buffer);
+
+        // converting 5-word frame into 20 bytes
+        j = offset;
+        for ( i = HASH_OFFSET; i < HASH_OFFSET +5; i++ ) {
+            int k = buffer[i];
+            digest[j  ] = (byte) ( k >>>24 );   // getting first  byte from left
+            digest[j+1] = (byte) ( k >>>16 );   // getting second byte from left
+            digest[j+2] = (byte) ( k >>> 8 );   // getting third  byte from left
+            digest[j+3] = (byte) ( k       );   // getting fourth byte from left
+            j += 4;
+        }
+
+        engineReset();
+    }
+
+    //  methods specified in java.security.MessageDigestSpi
+
+    /**
+     * Returns a "deep" copy of this SHA1MDImpl object. <BR>
+     *
+     * The method overrides "clone()" in class Object. <BR>
+     *
+     * @return
+     *       a clone of this object
+     */
+    public Object clone() throws CloneNotSupportedException {
+
+        SHA1_MessageDigestImpl cloneObj = (SHA1_MessageDigestImpl) super.clone();
+
+        cloneObj.buffer  = ( int[])buffer.clone();
+        cloneObj.oneByte = (byte[])oneByte.clone();
+
+        return cloneObj;
+    }
+
+
+    /**
+     * Computes a message digest value. <BR>
+     *
+     * The method resets the engine. <BR>
+     *
+     * The method overrides "engineDigest()" in class MessageDigestSpi. <BR>
+     *
+     * @return
+     *       byte array containing message digest value
+     */
+    protected byte[] engineDigest() {
+
+        byte[] hash = new byte[DIGEST_LENGTH];
+
+        processDigest(hash, 0);
+        return hash;
+    }
+
+
+    /**
+     * Computes message digest value.
+     * Upon return, the value is stored in "buf" buffer beginning "offset" byte. <BR>
+     *
+     * The method resets the engine. <BR>
+     *
+     * The method overrides "engineDigest(byte[],int,int) in class MessageDigestSpi. 
+     *
+     * @param
+     *       buf    byte array to store a message digest returned      
+     * @param            
+     *       offset a position in the array for first byte of the message digest   
+     * @param
+     *       len    number of bytes within buffer allotted for the message digest; 
+     *                as this implementation doesn't provide partial digests,        
+     *                len should be >= 20, DigestException is thrown otherwise       
+     * @return
+     *       the length of the message digest stored in the "buf" buffer;            
+     *       in this implementation the length=20
+     *
+     * @throws IllegalArgumentException       
+     *               if null is passed to the "buf" argument <BR>
+     *               if offset + len > buf.length  <BR>
+     *               if offset > buf.length or len > buf.length
+     *
+     * @throws DigestException          
+     *               if len < 20 
+     *
+     * @throws  ArrayIndexOutOfBoundsException 
+     *               if offset < 0
+     */
+    protected int engineDigest(byte[] buf, int offset, int len) throws DigestException { 
+
+        if ( buf == null ) {
+            throw new IllegalArgumentException(Messages.getString("security.162"));  //$NON-NLS-1$
+        }
+        if ( offset > buf.length || len > buf.length || (len + offset) > buf.length ) {
+            throw new IllegalArgumentException(
+               Messages.getString("security.163")); //$NON-NLS-1$
+        }
+        if ( len < DIGEST_LENGTH ) {
+            throw new DigestException(Messages.getString("security.164")); //$NON-NLS-1$
+        }
+        if ( offset < 0 ) {
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("security.165", offset)); //$NON-NLS-1$
+        }
+
+        processDigest(buf, offset);
+
+        return DIGEST_LENGTH;
+    }
+
+
+    /**
+     * Returns a message digest length. <BR>
+     *
+     * The method overrides "engineGetDigestLength()" in class MessageDigestSpi. <BR>
+     *
+     * @return
+     *        total length of current message digest as an int value
+     */
+    protected int engineGetDigestLength() { 
+        return DIGEST_LENGTH; 
+    }
+ 
+
+    /**
+     * Resets the engine. <BR>
+     *
+     * The method overrides "engineReset()" in class MessageDigestSpi. <BR>
+     */
+    protected void engineReset() {
+
+        messageLength = 0;
+
+        buffer[BYTES_OFFSET] = 0;
+        buffer[HASH_OFFSET   ] = H0;
+        buffer[HASH_OFFSET +1] = H1;
+        buffer[HASH_OFFSET +2] = H2;
+        buffer[HASH_OFFSET +3] = H3;
+        buffer[HASH_OFFSET +4] = H4;
+    }
+
+
+    /**
+     * Supplements a byte to current message. <BR>
+     *
+     * The method overrides "engineUpdate(byte)" in class MessageDigestSpi. <BR>
+     *
+     * @param
+     *       input byte to add to current message
+     */
+    protected void engineUpdate(byte input) {
+
+        oneByte[0] = input;
+        SHA1Impl.updateHash( buffer, oneByte, 0, 0 );
+        messageLength++;
+    }
+
+
+    /**
+     * Updates current message. <BR>
+     *
+     * The method overrides "engineUpdate(byte[],int,int)" in class MessageDigestSpi. <BR>
+     *
+     * The method silently returns if "len" <= 0.
+     *
+     * @param
+     *       input  a byte array
+     * @param
+     *       offset a number of first byte in the "input" array to use for updating
+     * @param
+     *       len    a number of bytes to use
+     *
+     * @throws NullPointerException     
+     *                if null is passed to the "buf" argument
+     *
+     * @throws IllegalArgumentException 
+     *                if offset > buf.length or len > buf.length or 
+     *                (len + offset) > buf.length
+     * @throws ArrayIndexOutOfBoundsException
+     *                offset < 0
+     */
+    protected void engineUpdate(byte[] input, int offset, int len) {
+
+        if ( input == null ) {
+            throw new IllegalArgumentException(Messages.getString("security.166"));  //$NON-NLS-1$
+        }
+        if ( len <= 0 ) {
+            return;
+        }
+        if ( offset < 0 ) {
+            throw new ArrayIndexOutOfBoundsException(Messages.getString("security.165", offset)); //$NON-NLS-1$
+        }
+        if ( offset > input.length || len > input.length || (len + offset) > input.length ) {
+            throw new IllegalArgumentException(
+               Messages.getString("security.167")); //$NON-NLS-1$
+        }
+
+        SHA1Impl.updateHash(buffer, input, offset, offset + len -1 );
+        messageLength += len;
+    }
+
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/SHA1withDSA_SignatureImpl.java b/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/SHA1withDSA_SignatureImpl.java
new file mode 100644
index 0000000..576ac76
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/SHA1withDSA_SignatureImpl.java
@@ -0,0 +1,436 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.security.provider.crypto;
+
+import java.math.BigInteger;
+
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SignatureException;
+
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAKey;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.DSAPublicKey;
+
+import java.security.MessageDigest;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+public class SHA1withDSA_SignatureImpl extends Signature {
+
+    private MessageDigest msgDigest;
+
+    private DSAKey dsaKey;
+
+    /**
+     * The solo constructor.
+     */
+    public SHA1withDSA_SignatureImpl() throws NoSuchAlgorithmException {
+
+        super("SHA1withDSA"); //$NON-NLS-1$
+
+        msgDigest = MessageDigest.getInstance("SHA1"); //$NON-NLS-1$
+    }
+
+    /**
+     * Deprecated method.
+     *
+     * @return
+     *    null
+     */
+    protected Object engineGetParameter(String param)
+            throws InvalidParameterException {
+        if (param == null) {
+            throw new NullPointerException(Messages.getString("security.01")); //$NON-NLS-1$
+        }
+        return null;
+    }
+
+    /**
+     * Initializes this signature object with PrivateKey object 
+     * passed as argument to the method.
+     *
+     * @params
+     *    privateKey DSAPrivateKey object
+     * @throws
+     *    InvalidKeyException if privateKey is not DSAPrivateKey object
+     */
+    protected void engineInitSign(PrivateKey privateKey)
+            throws InvalidKeyException {
+
+        DSAParams params;
+
+        // parameters and private key
+        BigInteger p, q, g, x;
+
+        int n;
+
+        if (privateKey == null || !(privateKey instanceof DSAPrivateKey)) {
+            throw new InvalidKeyException(
+                    Messages.getString("security.168")); //$NON-NLS-1$
+        }
+
+        params = ((DSAPrivateKey) privateKey).getParams();
+        p = params.getP();
+        q = params.getQ();
+        g = params.getG();
+        x = ((DSAPrivateKey) privateKey).getX();
+
+        // checks described in DSA standard
+        n = p.bitLength();
+        if (p.compareTo(BigInteger.valueOf(1)) != 1 || n < 512 || n > 1024
+                || (n & 077) != 0) {
+            throw new InvalidKeyException(Messages.getString("security.169")); //$NON-NLS-1$
+        }
+        if (q.signum() != 1 && q.bitLength() != 160) {
+            throw new InvalidKeyException(Messages.getString("security.16A")); //$NON-NLS-1$
+        }
+        if (x.signum() != 1 || x.compareTo(q) != -1) {
+            throw new InvalidKeyException(Messages.getString("security.16B")); //$NON-NLS-1$
+        }
+
+        dsaKey = (DSAKey) privateKey;
+
+        msgDigest.reset();
+    }
+
+    /**
+     * Initializes this signature object with PublicKey object 
+     * passed as argument to the method.
+     *
+     * @params
+     *    publicKey DSAPublicKey object
+     * @throws
+     *    InvalidKeyException if publicKey is not DSAPublicKey object
+     */
+    protected void engineInitVerify(PublicKey publicKey)
+            throws InvalidKeyException {
+
+        // parameters and public key
+        BigInteger p, q, g, y;
+
+        int n1;
+
+        if (publicKey == null || !(publicKey instanceof DSAPublicKey)) {
+            throw new InvalidKeyException(
+                    Messages.getString("security.16C")); //$NON-NLS-1$
+        }
+
+        DSAParams params = ((DSAPublicKey) publicKey).getParams();
+        p = params.getP();
+        q = params.getQ();
+        g = params.getG();
+        y = ((DSAPublicKey) publicKey).getY();
+
+        // checks described in DSA standard
+        n1 = p.bitLength();
+        if (p.compareTo(BigInteger.valueOf(1)) != 1 || n1 < 512 || n1 > 1024
+                || (n1 & 077) != 0) {
+            throw new InvalidKeyException(Messages.getString("security.169")); //$NON-NLS-1$
+        }
+        if (q.signum() != 1 || q.bitLength() != 160) {
+            throw new InvalidKeyException(Messages.getString("security.16A")); //$NON-NLS-1$
+        }
+        if (y.signum() != 1) {
+            throw new InvalidKeyException(Messages.getString("security.16D")); //$NON-NLS-1$
+        }
+
+        dsaKey = (DSAKey) publicKey;
+
+        msgDigest.reset();
+    }
+
+    /*
+     * Deprecated method.
+     *
+     * @throws
+     *    InvalidParameterException
+     */
+    protected void engineSetParameter(String param, Object value)
+            throws InvalidParameterException {
+        if (param == null) {
+            throw new NullPointerException(Messages.getString("security.83", "param")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        throw new InvalidParameterException(Messages.getString("security.16E")); //$NON-NLS-1$
+    }
+
+    /**
+     * Returns signature bytes as byte array containing 
+     * ASN1 representation for two BigInteger objects
+     * which is SEQUENCE of two INTEGERS.
+     * Length of sequence varies from less than 46 to 48.
+     *
+     * Resets object to the state it was in 
+     * when previous call to either "initSign" method was called.
+     *
+     * @return
+     *    byte array containing signature in ASN1 representation
+     * @throws
+     *    SignatureException if object's state is not SIGN or 
+     *                       signature algorithm cannot process data
+     */
+
+    protected byte[] engineSign() throws SignatureException {
+
+        // names of below BigIntegers are the same as they are defined in DSA standard
+        BigInteger r = null;
+        BigInteger s = null;
+        BigInteger k = null;
+
+        // parameters and private key
+        BigInteger p, q, g, x;
+
+        // BigInteger for message digest 
+        BigInteger digestBI;
+
+        // various byte array being used in computing signature
+        byte randomBytes[];
+        byte digest[];
+        byte rBytes[], sBytes[], signature[];
+
+        int n, n1, n2;
+
+        DSAParams params;
+
+        if (appRandom == null) {
+            appRandom = new SecureRandom();
+        }
+
+        params = dsaKey.getParams();
+        p = params.getP();
+        q = params.getQ();
+        g = params.getG();
+        x = ((DSAPrivateKey) dsaKey).getX();
+
+        // forming signature according algorithm described in chapter 5 of DSA standard
+
+        digestBI = new BigInteger(1, msgDigest.digest());
+
+        randomBytes = new byte[20];
+
+        for (;;) {
+
+            appRandom.nextBytes(randomBytes);
+
+            k = new BigInteger(1, randomBytes);
+            if (k.compareTo(q) != -1) {
+                continue;
+            }
+            r = g.modPow(k, p).mod(q);
+            if (r.signum() == 0) {
+                continue;
+            }
+
+            s = k.modInverse(q).multiply(digestBI.add(x.multiply(r)).mod(q))
+                    .mod(q);
+
+            if (s.signum() != 0) {
+                break;
+            }
+        }
+
+        // forming signature's ASN1 representation which is SEQUENCE of two INTEGERs
+        // 
+        rBytes = r.toByteArray();
+        n1 = rBytes.length;
+        if ((rBytes[0] & 0x80) != 0) {
+            n1++;
+        }
+        sBytes = s.toByteArray();
+        n2 = sBytes.length;
+        if ((sBytes[0] & 0x80) != 0) {
+            n2++;
+        }
+
+        signature = new byte[6 + n1 + n2]; // 48 is max. possible length of signature
+        signature[0] = (byte) 0x30; // ASN1 SEQUENCE tag
+        signature[1] = (byte) (4 + n1 + n2); // total length of two INTEGERs
+        signature[2] = (byte) 0x02; // ASN1 INTEGER tag
+        signature[3] = (byte) n1; // length of r
+        signature[4 + n1] = (byte) 0x02; // ASN1 INTEGER tag
+        signature[5 + n1] = (byte) n2; // length of s
+
+        if (n1 == rBytes.length) {
+            n = 4;
+        } else {
+            n = 5;
+        }
+        System.arraycopy(rBytes, 0, signature, n, rBytes.length);
+
+        if (n2 == sBytes.length) {
+            n = 6 + n1;
+        } else {
+            n = 7 + n1;
+        }
+        System.arraycopy(sBytes, 0, signature, n, sBytes.length);
+
+        return signature;
+    }
+
+    /**
+     * Updates data to sign or to verify.
+     *
+     * @params
+     *    b byte to update
+     * @throws
+     *    SignatureException if object was not initialized for signing or verifying
+     */
+    protected void engineUpdate(byte b) throws SignatureException {
+
+        msgDigest.update(b);
+    }
+
+    /**
+     * Updates data to sign or to verify.
+     *
+     * @params
+     *    b byte array containing bytes to update
+     * @params
+     *    off offset in byte array to start from
+     * @params
+     *    len number of bytes to use for updating
+     * @throws
+     *    SignatureException if object was not initialized for signing or verifying
+     */
+    protected void engineUpdate(byte[] b, int off, int len)
+            throws SignatureException {
+
+        msgDigest.update(b, off, len);
+    }
+
+    private boolean checkSignature(byte[] sigBytes, int offset, int length)
+            throws SignatureException {
+
+        // names of below BigIntegers are the same as they are defined in DSA standard
+        BigInteger r, s, w;
+        BigInteger u1, u2, v;
+
+        // parameters and public key
+        BigInteger p, q, g, y;
+
+        DSAParams params;
+
+        int n1, n2;
+
+        byte bytes[];
+        byte digest[];
+
+        // checking up on signature's ASN1
+        try {
+            byte dummy;
+            n1 = sigBytes[offset + 3];
+            n2 = sigBytes[offset + n1 + 5];
+
+            if (sigBytes[offset + 0] != 0x30 || sigBytes[offset + 2] != 2
+                    || sigBytes[offset + n1 + 4] != 2
+                    || sigBytes[offset + 1] != (n1 + n2 + 4) || n1 > 21
+                    || n2 > 21
+                    || (length != 0 && (sigBytes[offset + 1] + 2) > length)) {
+                throw new SignatureException(Messages.getString("security.16F")); //$NON-NLS-1$
+            }
+
+            dummy = sigBytes[5 + n1 + n2]; // to check length of sigBytes
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw new SignatureException(Messages.getString("security.170")); //$NON-NLS-1$
+        }
+
+        digest = msgDigest.digest();
+
+        bytes = new byte[n1];
+        System.arraycopy(sigBytes, offset + 4, bytes, 0, n1);
+        r = new BigInteger(bytes);
+
+        bytes = new byte[n2];
+        System.arraycopy(sigBytes, offset + 6 + n1, bytes, 0, n2);
+        s = new BigInteger(bytes);
+
+        params = dsaKey.getParams();
+        p = params.getP();
+        q = params.getQ();
+        g = params.getG();
+        y = ((DSAPublicKey) dsaKey).getY();
+
+        // forming signature according algorithm described in chapter 6 of DSA standard
+
+        if (r.signum() != 1 || r.compareTo(q) != -1 || s.signum() != 1
+                || s.compareTo(q) != -1) {
+            return false;
+        }
+
+        w = s.modInverse(q);
+
+        u1 = (new BigInteger(1, digest)).multiply(w).mod(q);
+        u2 = r.multiply(w).mod(q);
+
+        v = g.modPow(u1, p).multiply(y.modPow(u2, p)).mod(p).mod(q);
+
+        if (v.compareTo(r) != 0) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Verifies the signature bytes.
+     *
+     * @params
+     *    sigBytes byte array with signature bytes to verify.
+     * @return
+     *    true if signature bytes were verified, false otherwise
+     * @throws
+     *    SignatureException if object's state is not VERIFY or
+     *                       signature format is not ASN1 representation or
+     *                       signature algorithm cannot process data
+     */
+    protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
+
+        if (sigBytes == null) {
+            throw new NullPointerException(Messages.getString("security.83", "sigBytes")); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        return checkSignature(sigBytes, 0, 0);
+    }
+
+    /**
+     * Verifies the signature bytes.
+     *
+     * @params
+     *    sigBytes byte array with signature bytes to verify.
+     * @params
+     *    offset index in sigBytes to start from
+     * @params
+     *    length number of bytes allotted for signature
+     * @return
+     *    true if signature bytes were verified, false otherwise
+     * @throws
+     *    SignatureException if object's state is not VERIFY or
+     *                       signature format is not ASN1 representation or
+     *                       signature algorithm cannot process data
+     */
+    protected boolean engineVerify(byte[] sigBytes, int offset, int length)
+            throws SignatureException {
+        return checkSignature(sigBytes, offset, length);
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/ThreeIntegerSequence.java b/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/ThreeIntegerSequence.java
new file mode 100644
index 0000000..41eeb45
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/provider/crypto/ThreeIntegerSequence.java
@@ -0,0 +1,73 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+
+package org.apache.harmony.security.provider.crypto;
+
+import org.apache.harmony.security.asn1.ASN1Integer;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+
+
+/**
+ * The auxiliary class providing means to process ASN1Sequence of three Integers.
+ * Such sequences are parts of ASN1 encoded formats for DSA private and public keys. 
+ */
+class ThreeIntegerSequence {
+
+    byte[] p, q, g;
+
+    private byte[] encoding;
+
+    ThreeIntegerSequence(byte[] p, byte[] q, byte[] g) {
+
+        this.p = p;
+        this.q = q;
+        this.g = g;
+        encoding = null;
+    }
+
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
+            ASN1Integer.getInstance(), ASN1Integer.getInstance(),
+            ASN1Integer.getInstance() }) {
+
+        protected Object getDecodedObject(BerInputStream in) {
+
+            Object[] values = (Object[]) in.content;
+
+            return new ThreeIntegerSequence((byte[]) values[0],
+                    (byte[]) values[1], (byte[]) values[2]);
+        }
+
+        protected void getValues(Object object, Object[] values) {
+
+            ThreeIntegerSequence mySeq = (ThreeIntegerSequence) object;
+
+            values[0] = mySeq.p;
+            values[1] = mySeq.q;
+            values[2] = mySeq.g;
+        }
+    };
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/utils/AlgNameMapper.java b/libcore/security/src/main/java/org/apache/harmony/security/utils/AlgNameMapper.java
new file mode 100644
index 0000000..2381ec0
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/utils/AlgNameMapper.java
@@ -0,0 +1,248 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.utils;
+
+import java.security.Provider;
+import java.security.Security;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import org.apache.harmony.security.asn1.ObjectIdentifier;
+
+/**
+ * Provides Algorithm Name to OID
+ * and OID to Algorithm Name mappings.
+ * Some known mappings are hardcoded.
+ * Tries to obtain additional mappings
+ * from installed providers during initialization.
+ * 
+ * Hardcoded mappings
+ * (source: http://asn1.elibel.tm.fr):
+ * 
+ * 1.2.840.10040.4.1 -> DSA
+ * 
+ * 1.2.840.113549.1.1.1 -> RSA
+ * 
+ * 1.2.840.113549.1.3.1 -> DiffieHellman
+ * 
+ * 1.2.840.113549.1.5.3 -> PBEWithMD5AndDES
+ * 
+ * 1.2.840.113549.1.12.1.3 -> pbeWithSHAAnd3-KeyTripleDES-CBC
+ * 1.2.840.113549.1.12.1.3 -> PBEWithSHA1AndDESede
+ * 1.2.840.113549.1.12.1.3 -> PBEWithSHA1AndTripleDES
+ * 
+ * 1.2.840.113549.1.12.1.6 -> pbeWithSHAAnd40BitRC2-CBC
+ * 1.2.840.113549.1.12.1.6 -> PBEWithSHA1AndRC2_40
+ * 
+ * 1.2.840.113549.3.2 -> RC2-CBC
+ * 1.2.840.113549.3.3 -> RC2-EBC
+ * 1.2.840.113549.3.4 -> RC4
+ * 1.2.840.113549.3.5 -> RC4WithMAC
+ * 1.2.840.113549.3.6 -> DESx-CBC
+ * 1.2.840.113549.3.7 -> TripleDES-CBC
+ * 1.2.840.113549.3.8 -> rc5CBC
+ * 1.2.840.113549.3.9 -> RC5-CBC
+ * 1.2.840.113549.3.10 -> DESCDMF (CDMFCBCPad)
+ *  
+ */
+public class AlgNameMapper {
+    
+    // Will search OID mappings for these services
+    private static final String[] serviceName = {
+            "Cipher", //$NON-NLS-1$
+            "AlgorithmParameters", //$NON-NLS-1$
+            "Signature" //$NON-NLS-1$
+    };
+
+    // These mappings CAN NOT be overridden
+    // by the ones from available providers
+    // during maps initialization
+    // (source: http://asn1.elibel.tm.fr):
+    private static final String[][] knownAlgMappings = {
+        {"1.2.840.10040.4.1",       "DSA"}, //$NON-NLS-1$ //$NON-NLS-2$
+        {"1.2.840.10040.4.3",       "SHA1withDSA"}, //$NON-NLS-1$ //$NON-NLS-2$
+        {"1.2.840.113549.1.1.1",    "RSA"}, //$NON-NLS-1$ //$NON-NLS-2$
+        {"1.2.840.113549.1.1.2",    "MD2withRSA"}, //$NON-NLS-1$ //$NON-NLS-2$
+        {"1.2.840.113549.1.1.4",    "MD5withRSA"}, //$NON-NLS-1$ //$NON-NLS-2$
+        {"1.2.840.113549.1.1.5",    "SHA1withRSA"}, //$NON-NLS-1$ //$NON-NLS-2$
+        {"1.2.840.113549.1.3.1",    "DiffieHellman"}, //$NON-NLS-1$ //$NON-NLS-2$
+        {"1.2.840.113549.1.5.3",    "pbeWithMD5AndDES-CBC"}, //$NON-NLS-1$ //$NON-NLS-2$
+        {"1.2.840.113549.1.12.1.3", "pbeWithSHAAnd3-KeyTripleDES-CBC"}, //$NON-NLS-1$ //$NON-NLS-2$
+        {"1.2.840.113549.1.12.1.6", "pbeWithSHAAnd40BitRC2-CBC"}, //$NON-NLS-1$ //$NON-NLS-2$
+        {"1.2.840.113549.3.2",      "RC2-CBC"}, //$NON-NLS-1$ //$NON-NLS-2$
+        {"1.2.840.113549.3.3",      "RC2-EBC"}, //$NON-NLS-1$ //$NON-NLS-2$
+        {"1.2.840.113549.3.4",      "RC4"}, //$NON-NLS-1$ //$NON-NLS-2$
+        {"1.2.840.113549.3.5",      "RC4WithMAC"}, //$NON-NLS-1$ //$NON-NLS-2$
+        {"1.2.840.113549.3.6",      "DESx-CBC"}, //$NON-NLS-1$ //$NON-NLS-2$
+        {"1.2.840.113549.3.7",      "TripleDES-CBC"}, //$NON-NLS-1$ //$NON-NLS-2$
+        {"1.2.840.113549.3.8",      "rc5CBC"}, //$NON-NLS-1$ //$NON-NLS-2$
+        {"1.2.840.113549.3.9",      "RC5-CBC"}, //$NON-NLS-1$ //$NON-NLS-2$
+        {"1.2.840.113549.3.10",     "DESCDMF"}, //$NON-NLS-1$ //$NON-NLS-2$
+        {"2.23.42.9.11.4.1",        "ECDSA"}, //$NON-NLS-1$ //$NON-NLS-2$
+    };
+    // Maps alg name to OID
+    private static final Map<String, String> alg2OidMap = new HashMap<String, String>();
+    // Maps OID to alg name
+    private static final Map<String, String> oid2AlgMap = new HashMap<String, String>();
+    // Maps aliases to alg names
+    private static final Map<String, String> algAliasesMap = new HashMap<String, String>();
+
+    static {
+        for (String[] element : knownAlgMappings) {
+            String algUC = element[1].toUpperCase();
+            alg2OidMap.put(algUC, element[0]);
+            oid2AlgMap.put(element[0], algUC);
+            // map upper case alg name to its original name
+            algAliasesMap.put(algUC, element[1]);
+        }
+        //
+        // Now search providers for mappings like
+        // Alg.Alias.<service>.<OID-INTS-DOT-SEPARATED>=<alg-name>
+        //  or
+        // Alg.Alias.<service>.OID.<OID-INTS-DOT-SEPARATED>=<alg-name>
+        //
+        Provider[] pl = Security.getProviders();
+        for (Provider element : pl) {
+            selectEntries(element);
+        }
+    }
+
+    // No instances 
+    private AlgNameMapper() {
+    }
+  
+    /**
+     * Returns OID for algName
+     *
+     * @param algName algorithm name to be mapped
+     * @return OID as String
+     */
+    public static String map2OID(String algName) {
+        // alg2OidMap map contains upper case keys
+        return alg2OidMap.get(algName.toUpperCase());
+    }
+
+    /**
+     * Returns algName for OID
+     *
+     * @param oid OID to be mapped
+     * @return algorithm name
+     */
+    public static String map2AlgName(String oid) {
+        // oid2AlgMap map contains upper case values
+        String algUC = oid2AlgMap.get(oid);
+        // if not null there is always map UC->Orig
+        return algUC == null ? null : algAliasesMap.get(algUC);
+    }
+
+    /**
+     * Returns Algorithm name for given algorithm alias
+     *
+     * @param algName - alias
+     * @return algorithm name
+     */
+    public static String getStandardName(String algName) {
+        return algAliasesMap.get(algName.toUpperCase());
+    }
+
+    // Searches given provider for mappings like
+    // Alg.Alias.<service>.<OID-INTS-DOT-SEPARATED>=<alg-name>
+    //  or
+    // Alg.Alias.<service>.OID.<OID-INTS-DOT-SEPARATED>=<alg-name>
+    // Puts mappings found into appropriate internal maps
+    private static void selectEntries(Provider p) {
+        Set<Map.Entry<Object, Object>> entrySet = p.entrySet();
+        for (String service : serviceName) {
+            String keyPrfix2find = "Alg.Alias." + service + ".";  //$NON-NLS-1$ //$NON-NLS-2$
+            for (Entry<Object, Object> me : entrySet) {
+                String key = (String)me.getKey();
+                if (key.startsWith(keyPrfix2find)) {
+                    String alias = key.substring(keyPrfix2find.length());
+                    String alg = (String)me.getValue();
+                    String algUC = alg.toUpperCase();
+                    if (isOID(alias)) {
+                        if (alias.startsWith("OID.")) { //$NON-NLS-1$
+                            alias = alias.substring(4);
+                        }
+                        // Do not overwrite already known mappings
+                        boolean oid2AlgContains = oid2AlgMap.containsKey(alias);
+                        boolean alg2OidContains = alg2OidMap.containsKey(algUC);
+                        if (!oid2AlgContains || !alg2OidContains) {
+                            if (!oid2AlgContains) {
+                                oid2AlgMap.put(alias, algUC);
+                            } 
+                            if (!alg2OidContains) {
+                                alg2OidMap.put(algUC, alias);
+                            }
+                            // map upper case alg name to its original name
+                            algAliasesMap.put(algUC, alg);
+                        }
+                           // Do not override known standard names
+                    } else if (!algAliasesMap.containsKey(alias.toUpperCase())) {
+                        algAliasesMap.put(alias.toUpperCase(), alg);
+                    }
+                }
+            }
+        }
+    }
+    
+    /**
+     * Checks if parameter represents OID
+     *
+     * @param alias alias to be checked
+     * @return 'true' if parameter represents OID 
+     */
+    public static boolean isOID(String alias) {
+        // BEGIN android-changed
+        return ObjectIdentifier.isOID(normalize(alias));
+        // END android-changed
+    }
+
+    /**
+     * Removes leading "OID." from oid String passed
+     *
+     * @param oid string that may contain leading "OID."
+     * @return string passed without leading "OID." 
+     */
+    public static String normalize(String oid) {
+        return oid.startsWith("OID.") //$NON-NLS-1$
+            ? oid.substring(4)
+            : oid;
+    }
+
+    /**
+     * Present all internal maps as formatted string
+     * @return Internal maps String representation
+     */
+    public static String dump() {
+        StringBuffer sb = new StringBuffer("alg2OidMap: "); //$NON-NLS-1$
+        sb.append(alg2OidMap);
+        sb.append("\noid2AlgMap: "); //$NON-NLS-1$
+        sb.append(oid2AlgMap);
+        sb.append("\nalgAliasesMap: "); //$NON-NLS-1$
+        sb.append(algAliasesMap);
+        return sb.toString();
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/utils/Array.java b/libcore/security/src/main/java/org/apache/harmony/security/utils/Array.java
new file mode 100644
index 0000000..dc74202
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/utils/Array.java
@@ -0,0 +1,107 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.utils;
+
+
+/**
+ * Utility class for arrays
+ * 
+ */
+public class Array {
+
+    // No instances of this class
+    private Array() {
+    }
+
+    /**
+     * Represents <code>array</code> as <code>String</code>
+     * for printing. Array length can be up to 32767
+     *
+     * @param array to be represented as <code>String</code>
+     * 
+     * @return <code>String</code> representation of the <code>array</code>
+     */
+    public static String toString(byte[] array, String prefix) {
+        // Prefixes to be added to the offset values
+        // in <code>String toString(byte[], String)</code> method
+        final String[] offsetPrefix = {
+                "", //$NON-NLS-1$
+                "000", //$NON-NLS-1$
+                "00", //$NON-NLS-1$
+                "0", //$NON-NLS-1$
+                "" //$NON-NLS-1$
+        };
+        StringBuilder sb = new StringBuilder();
+        StringBuilder charForm = new StringBuilder();
+        int i=0;
+        for (i=0; i<array.length; i++) {
+            if (i%16 == 0) {
+                sb.append(prefix);
+                // put offset
+                String offset = Integer.toHexString(i);
+                sb.append(offsetPrefix[offset.length()]);
+                sb.append(offset);
+                // clear char form for new line
+                charForm.delete(0, charForm.length());
+            }
+            // put delimiter
+            sb.append(' ');
+            // put current byte
+            int currentByte = (0xff & array[i]);
+            String hexTail = Integer.toHexString(currentByte);
+            if (hexTail.length() == 1) {
+                sb.append('0');
+            }
+            sb.append(hexTail);
+            // form character representation part
+            char currentChar = (char)(currentByte & 0xffff);
+            // FIXME if needed (how to distinguish PRINTABLE chars?)
+            charForm.append(
+                    (Character.isISOControl(currentChar) ? '.' : currentChar));
+            // Add additional delimiter for each 8 values
+            if ((i+1)%8 == 0) {
+                sb.append(' ');
+            }
+            // Add character representation for each line
+            if ((i+1)%16 == 0) {
+                sb.append(' ');
+                sb.append(charForm.toString());
+                sb.append('\n');
+            }
+        }
+        // form last line
+        if (i%16 != 0) {
+            int ws2add = 16 - i%16;
+            for (int j=0; j<ws2add; j++) {
+                sb.append("   "); //$NON-NLS-1$
+            }
+            if (ws2add > 8) {
+                sb.append(' ');
+            }
+            sb.append("  "); //$NON-NLS-1$
+            sb.append(charForm.toString());
+            sb.append('\n');
+        }
+        return sb.toString();
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/utils/JarUtils.java b/libcore/security/src/main/java/org/apache/harmony/security/utils/JarUtils.java
new file mode 100644
index 0000000..e19e14a
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/utils/JarUtils.java
@@ -0,0 +1,236 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris Kuznetsov
+* @version $Revision$
+*/
+package org.apache.harmony.security.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.Signature;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.internal.nls.Messages;
+import org.apache.harmony.security.pkcs7.ContentInfo;
+import org.apache.harmony.security.pkcs7.SignedData;
+import org.apache.harmony.security.pkcs7.SignerInfo;
+import org.apache.harmony.security.provider.cert.X509CertImpl;
+import org.apache.harmony.security.x501.AttributeTypeAndValue;
+
+// BEGIN android-added
+import org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigestJDK;
+import org.apache.harmony.xnet.provider.jsse.OpenSSLSignature;
+// END android-added
+
+public class JarUtils {
+
+    // as defined in PKCS #9: Selected Attribute Types:
+    // http://www.ietf.org/rfc/rfc2985.txt
+    private static final int[] MESSAGE_DIGEST_OID =
+        new int[] {1, 2, 840, 113549, 1, 9, 4};
+
+    /**
+     * This method handle all the work with  PKCS7, ASN1 encoding, signature verifying, 
+     * and certification path building. 
+     * See also PKCS #7: Cryptographic Message Syntax Standard:
+     * http://www.ietf.org/rfc/rfc2315.txt
+     * @param signature - the input stream of signature file to be verified
+     * @param signatureBlock - the input stream of corresponding signature block file
+     * @return array of certificates used to verify the signature file
+     * @throws IOException - if some errors occurs during reading from the stream
+     * @throws GeneralSecurityException - if signature verification process fails
+     */
+    public static Certificate[] verifySignature(InputStream signature, InputStream 
+            signatureBlock) throws IOException, GeneralSecurityException {
+
+        BerInputStream bis = new BerInputStream(signatureBlock);
+        ContentInfo info = (ContentInfo)ContentInfo.ASN1.decode(bis);      
+        SignedData signedData = info.getSignedData();
+        if (signedData == null) {
+            throw new IOException(Messages.getString("security.173")); //$NON-NLS-1$
+        }
+        Collection encCerts = signedData.getCertificates();
+        if (encCerts.isEmpty()) {
+            return null;
+        }
+        X509Certificate[] certs = new X509Certificate[encCerts.size()];
+        int i = 0;
+        for (Iterator it = encCerts.iterator(); it.hasNext();) {
+            certs[i++]= new X509CertImpl((org.apache.harmony.security.x509.Certificate)it.next());
+        }
+
+        List sigInfos = signedData.getSignerInfos();
+        SignerInfo sigInfo;
+        if (!sigInfos.isEmpty()) {
+            sigInfo = (SignerInfo)sigInfos.get(0);
+        } else {
+            return null;
+        }
+
+        // Issuer
+        X500Principal issuer = sigInfo.getIssuer();
+
+        // Certificate serial number
+        BigInteger snum = sigInfo.getSerialNumber();
+
+        // Locate the certificate
+        int issuerSertIndex = 0;
+        for (i = 0; i < certs.length; i++) {
+            if (issuer.equals(certs[i].getIssuerDN()) && 
+                    snum.equals(certs[i].getSerialNumber())) {
+                issuerSertIndex = i;
+                break;
+            }
+        }
+        if (i == certs.length) { // No issuer certificate found
+            return null;
+        }
+
+        if (certs[issuerSertIndex].hasUnsupportedCriticalExtension()) {
+            throw new SecurityException(Messages.getString("security.174")); //$NON-NLS-1$
+        }
+
+        // Get Signature instance
+        Signature sig = null;
+        String da = sigInfo.getdigestAlgorithm();
+        String dea = sigInfo.getDigestEncryptionAlgorithm();
+        String alg = null;
+        if (da != null && dea != null) {
+            alg = da + "with" +  dea; //$NON-NLS-1$
+            try{ 
+                // BEGIN android-removed
+                // sig = OpenSSLSignature.getInstance(alg);
+                // END android-removed
+                // BEGIN android-added
+                sig = OpenSSLSignature.getInstance(alg);
+                // END android-removed
+            } catch (NoSuchAlgorithmException e) {}
+        }
+        if (sig == null) {
+            alg = da;
+            if (alg == null) {
+                return null;
+            }
+            try{ 
+                // BEGIN android-removed
+                // sig = OpenSSLSignature.getInstance(alg);
+                // END android-removed
+                // BEGIN android-added
+                sig = OpenSSLSignature.getInstance(alg);
+                // END android-removed
+            } catch (NoSuchAlgorithmException e) {
+                return null;
+            }
+        }
+        sig.initVerify(certs[issuerSertIndex]);
+
+        // If the authenticatedAttributes field of SignerInfo contains more than zero attributes,
+        // compute the message digest on the ASN.1 DER encoding of the Attributes value.
+        // Otherwise, compute the message digest on the data.
+        List atr = sigInfo.getAuthenticatedAttributes();
+
+        byte[] sfBytes = new byte[signature.available()];
+        signature.read(sfBytes);
+
+        if (atr == null) {
+            sig.update(sfBytes);    
+        } else {
+            sig.update(sigInfo.getEncodedAuthenticatedAttributes());
+
+            // If the authenticatedAttributes field contains the message-digest attribute,
+            // verify that it equals the computed digest of the signature file
+            byte[] existingDigest = null;
+            for (Iterator it = atr.iterator(); it.hasNext();) {
+                AttributeTypeAndValue a = (AttributeTypeAndValue)it.next();
+                if (Arrays.equals(a.getType().getOid(), MESSAGE_DIGEST_OID) ){
+//TODO value                    existingDigest = a.AttributeValue;
+                }
+            }
+            if (existingDigest != null) {
+                // BEGIN android-removed
+                // MessageDigest md = MessageDigest.getInstance(sigInfo.getDigestAlgorithm());
+                // END android-removed
+                // BEGIN android-added
+                MessageDigest md = OpenSSLMessageDigestJDK.getInstance(sigInfo.getDigestAlgorithm());
+                // END android-added
+                byte[] computedDigest = md.digest(sfBytes);
+                if (!Arrays.equals(existingDigest, computedDigest)) {
+                    throw new SecurityException(Messages.getString("security.175")); //$NON-NLS-1$
+                }
+            }
+        }
+
+        if (!sig.verify(sigInfo.getEncryptedDigest())) {
+            throw new SecurityException(Messages.getString("security.176")); //$NON-NLS-1$
+        }
+
+        return createChain(certs[issuerSertIndex], certs);
+    }
+    
+    private static X509Certificate[] createChain(X509Certificate  signer, X509Certificate[] candidates) {
+        LinkedList chain = new LinkedList();
+        chain.add(0, signer);
+
+        // Signer is self-signed
+        if (signer.getSubjectDN().equals(signer.getIssuerDN())){
+            return (X509Certificate[])chain.toArray(new X509Certificate[1]);
+        }
+
+        Principal issuer = signer.getIssuerDN();
+        X509Certificate issuerCert;
+        int count = 1;
+        while (true) {
+            issuerCert = findCert(issuer, candidates);
+            if( issuerCert == null) {
+                break;
+            }
+            chain.add(issuerCert);
+            count++;
+            if (issuerCert.getSubjectDN().equals(issuerCert.getIssuerDN())) {
+                break;
+            }
+            issuer = issuerCert.getIssuerDN();
+        }
+        return (X509Certificate[])chain.toArray(new X509Certificate[count]);
+    }
+
+    private static X509Certificate findCert(Principal issuer, X509Certificate[] candidates) {
+        for (int i = 0; i < candidates.length; i++) {
+            if (issuer.equals(candidates[i].getSubjectDN())) {
+                return candidates[i];
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/utils/ObjectIdentifier.java b/libcore/security/src/main/java/org/apache/harmony/security/utils/ObjectIdentifier.java
new file mode 100644
index 0000000..517e096
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/utils/ObjectIdentifier.java
@@ -0,0 +1,222 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+/**
+* @author Alexander V. Esin, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.utils;
+
+import java.util.Arrays;
+
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * Instance of this class represents ObjectIdentifier (OID).
+ * 
+ * OID is represented as a sequence of subidentifier.
+ * Each subidentifier is represented as non negative integer value.
+ * There are at least 2 subidentifiers in the sequence.
+ * 
+ * Valid values for first subidentifier are 0, 1 and 2.
+ * If the first subidentifier has 0 or 1 value the second
+ * subidentifier MUST be less then 40.
+ * 
+ * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
+ */
+
+public final class ObjectIdentifier {
+
+    //OID as array of integers
+    private final int[] oid;
+
+    //hash code
+    private int hash = -1;
+
+    //OID as string
+    private String soid;
+
+    // stores the following: "OID." + soid
+    private String sOID;
+
+    // OID alias name
+    private String name;
+
+    // OID's group
+    private Object group;
+
+    /**
+     * Creates ObjectIdentifier(OID) from array of integers.
+     * 
+     * @param oid - array of integers
+     * @return - OID object
+     * @throws NullPointerException     - if oid is null
+     * @throws IllegalArgumentException - if oid is invalid
+     */
+    public ObjectIdentifier(int[] oid) {
+
+        validateOid(oid);
+
+        this.oid = oid;
+    }
+
+    /**
+     * Creates ObjectIdentifier(OID) from array of integers.
+     * 
+     * @param oid - array of integers
+     * @param name - name of OID
+     * @param oidGroup - OID's group. Is used to separate different OID's
+     * @return - OID object
+     * @throws NullPointerException     - if oid is null
+     * @throws IllegalArgumentException - if oid is invalid
+     */
+    public ObjectIdentifier(int[] oid, String name, Object oidGroup) {
+        this(oid);
+
+        if (oidGroup == null) {
+            throw new NullPointerException(Messages.getString("security.172")); //$NON-NLS-1$
+        }
+        this.group = oidGroup;
+
+        this.name = name;
+        toOIDString(); // init soid & sOID
+    }
+
+    /**
+     * Gets OID.
+     * 
+     * @return oid
+     */
+    public int[] getOid() {
+        return oid;
+    }
+    
+    /**
+     * Gets OID's name.
+     * 
+     * @return name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Gets OID's group.
+     * 
+     * @return group
+     */
+    public Object getGroup() {
+        return group;
+    }
+
+    /**
+     * Compares object with OID for equality.
+     * 
+     * @return true if object is ObjectIdentifier and it has the same
+     *         representation as array of integers, otherwise false
+     */
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || this.getClass() != o.getClass()) {
+            return false;
+        }
+        return Arrays.equals(oid, ((ObjectIdentifier) o).oid);
+    }
+
+    /**
+     * Add "OID." to the beginning of string representation.
+     * 
+     * @return oid as string
+     */
+    public String toOIDString() {
+        if (sOID == null) {
+            sOID = "OID." + toString(); //$NON-NLS-1$
+        }
+        return sOID;
+    }
+
+    /**
+     * Overrides Object.toString()
+     * 
+     * @return oid as string
+     */
+    public String toString() {
+        if (soid == null) {
+            StringBuffer sb = new StringBuffer(4 * oid.length);
+
+            for (int i = 0; i < oid.length - 1; ++i) {
+                sb.append(oid[i]);
+                sb.append('.');
+            }
+            sb.append(oid[oid.length - 1]);
+            soid = sb.toString();
+        }
+        return soid;
+    }
+
+    /**
+     * @see java.lang.Object#hashCode()
+     */
+    public int hashCode() {
+        if (hash == -1) {
+            hash = hashIntArray(oid);
+        }
+        return hash;
+    }
+
+    /**
+     * Validates ObjectIdentifier (OID).
+     * 
+     * @param oid - oid as array of integers
+     * @throws NullPointerException     - if oid is null
+     * @throws IllegalArgumentException - if oid is invalid
+     */
+    public static void validateOid(int[] oid) {
+
+        if (oid == null) {
+            throw new NullPointerException(Messages.getString("security.98")); //$NON-NLS-1$
+        }
+
+        if (oid.length < 2) {
+            throw new IllegalArgumentException(
+                    Messages.getString("security.99")); //$NON-NLS-1$
+        }
+
+        if (oid[0] > 2) {
+            throw new IllegalArgumentException(
+                    Messages.getString("security.9A")); //$NON-NLS-1$
+        } else if (oid[0] != 2 && oid[1] > 39) {
+            throw new IllegalArgumentException(
+                    Messages.getString("security.9B")); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Returns hash code for array of integers
+     * 
+     * @param oid - array of integers
+     */
+    public static int hashIntArray(int[] array) {
+        int intHash = 0;
+        for (int i = 0; i < array.length && i < 4; i++) {
+            intHash += array[i] << (8 * i); //TODO what about to find better one?
+        }
+        return intHash & 0x7FFFFFFF; // only positive
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x501/AttributeType.java b/libcore/security/src/main/java/org/apache/harmony/security/x501/AttributeType.java
new file mode 100644
index 0000000..a730e4f
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x501/AttributeType.java
@@ -0,0 +1,46 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+/**
+* @author Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x501;
+
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.ObjectIdentifier;
+
+
+/**
+ * X.501 Attribute Type
+ * 
+ * This is a draft class for Module InformationFramework (X.501).
+ * 
+ * @see <a href="http://www.itu.int/ITU-T/asn1/database/itu-t/x/x501/2001/InformationFramework.html">X.501</a>
+ */
+
+public class AttributeType {
+
+    public final ObjectIdentifier oid;
+
+    public final ASN1Type type;
+
+    public AttributeType(ObjectIdentifier oid, ASN1Type type) {
+        this.oid = oid;
+        this.type = type;
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x501/AttributeTypeAndValue.java b/libcore/security/src/main/java/org/apache/harmony/security/x501/AttributeTypeAndValue.java
new file mode 100644
index 0000000..c8f9494
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x501/AttributeTypeAndValue.java
@@ -0,0 +1,540 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Esin, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x501;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.asn1.ASN1Constants;
+import org.apache.harmony.security.asn1.ASN1Oid;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1StringType;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.asn1.BerOutputStream;
+import org.apache.harmony.security.internal.nls.Messages;
+import org.apache.harmony.security.utils.ObjectIdentifier;
+
+
+/**
+ * X.501 AttributeTypeAndValue
+ */
+public class AttributeTypeAndValue {
+
+    // Country code attribute (name from RFC 1779)
+    private static final ObjectIdentifier C;
+
+    // Common name attribute (name from RFC 1779)
+    private static final ObjectIdentifier CN;
+
+    // Domain component attribute (name from RFC 2253)
+    private static final ObjectIdentifier DC;
+
+    // DN qualifier attribute (name from API spec)
+    private static final ObjectIdentifier DNQ;
+
+    private static final ObjectIdentifier DNQUALIFIER;
+
+    // Email Address attribute (name from API spec)
+    private static final ObjectIdentifier EMAILADDRESS;
+
+    // Generation attribute (qualifies an individual's name)
+    // (name from API spec)
+    private static final ObjectIdentifier GENERATION;
+
+    // Given name attribute (name from API spec)
+    private static final ObjectIdentifier GIVENNAME;
+
+    // Initials attribute (initials of an individual's name)
+    // (name from API spec)
+    private static final ObjectIdentifier INITIALS;
+
+    // Name of a locality attribute (name from RFC 1779)
+    private static final ObjectIdentifier L;
+
+    // Organization name attribute (name from RFC 1779)
+    private static final ObjectIdentifier O;
+
+    // Organizational unit name attribute (name from RFC 1779)
+    private static final ObjectIdentifier OU;
+
+    // Serial number attribute (serial number of a device)
+    // (name from API spec)
+    private static final ObjectIdentifier SERIALNUMBER;
+
+    // Attribute for the full name of a state or province
+    // (name from RFC 1779)
+    private static final ObjectIdentifier ST;
+
+    // Street attribute (name from RFC 1779)
+    private static final ObjectIdentifier STREET;
+
+    // Surname attribute (comes from an individual's parent name) 
+    // (name from API spec)
+    private static final ObjectIdentifier SURNAME;
+
+    // Title attribute (object in an organization)(name from API spec)
+    private static final ObjectIdentifier T;
+
+    // User identifier attribute (name from RFC 2253)
+    private static final ObjectIdentifier UID;
+
+    //
+    // OID's pool
+    //
+
+    // pool's capacity
+    private static final int CAPACITY;
+
+    // pool's size
+    private static final int SIZE;
+
+    // pool: contains all recognizable attribute type keywords
+    private static final ObjectIdentifier[][] KNOWN_OIDS;
+
+    // known keywords attribute
+    private static final HashMap KNOWN_NAMES = new HashMap(30);
+
+    // known attribute types for RFC1779 (see Table 1)
+    private static final HashMap RFC1779_NAMES = new HashMap(10);
+
+    // known attribute types for RFC2253
+    // (see 2.3.  Converting AttributeTypeAndValue)
+    private static final HashMap RFC2253_NAMES = new HashMap(10);
+
+    // known attribute types for RFC2459 (see API spec.)
+    private static final HashMap RFC2459_NAMES = new HashMap(10);
+
+    static {
+
+        // pool initialization
+        CAPACITY = 10;
+        SIZE = 10;
+        KNOWN_OIDS = new ObjectIdentifier[SIZE][CAPACITY];
+
+        // init known attribute type keywords
+        C = new ObjectIdentifier(new int[] { 2, 5, 4, 6 }, "C", RFC1779_NAMES); //$NON-NLS-1$
+        CN = new ObjectIdentifier(new int[] { 2, 5, 4, 3 }, "CN", RFC1779_NAMES); //$NON-NLS-1$
+
+        DC = new ObjectIdentifier(
+                new int[] { 0, 9, 2342, 19200300, 100, 1, 25 }, "DC", //$NON-NLS-1$
+                RFC2253_NAMES);
+        // DN qualifier aliases
+        DNQ = new ObjectIdentifier(new int[] { 2, 5, 4, 46 }, "DNQ", //$NON-NLS-1$
+                RFC2459_NAMES);
+        DNQUALIFIER = new ObjectIdentifier(new int[] { 2, 5, 4, 46 },
+                "DNQUALIFIER", RFC2459_NAMES); //$NON-NLS-1$
+
+        EMAILADDRESS = new ObjectIdentifier(new int[] { 1, 2, 840, 113549, 1,
+                9, 1 }, "EMAILADDRESS", RFC2459_NAMES); //$NON-NLS-1$
+
+        GENERATION = new ObjectIdentifier(new int[] { 2, 5, 4, 44 },
+                "GENERATION", RFC2459_NAMES); //$NON-NLS-1$
+        GIVENNAME = new ObjectIdentifier(new int[] { 2, 5, 4, 42 },
+                "GIVENNAME", RFC2459_NAMES); //$NON-NLS-1$
+
+        INITIALS = new ObjectIdentifier(new int[] { 2, 5, 4, 43 }, "INITIALS", //$NON-NLS-1$
+                RFC2459_NAMES);
+
+        L = new ObjectIdentifier(new int[] { 2, 5, 4, 7 }, "L", RFC1779_NAMES); //$NON-NLS-1$
+
+        O = new ObjectIdentifier(new int[] { 2, 5, 4, 10 }, "O", RFC1779_NAMES); //$NON-NLS-1$
+        OU = new ObjectIdentifier(new int[] { 2, 5, 4, 11 }, "OU", //$NON-NLS-1$
+                RFC1779_NAMES);
+
+        SERIALNUMBER = new ObjectIdentifier(new int[] { 2, 5, 4, 5 },
+                "SERIALNUMBER", RFC2459_NAMES); //$NON-NLS-1$
+        ST = new ObjectIdentifier(new int[] { 2, 5, 4, 8 }, "ST", RFC1779_NAMES); //$NON-NLS-1$
+        STREET = new ObjectIdentifier(new int[] { 2, 5, 4, 9 }, "STREET", //$NON-NLS-1$
+                RFC1779_NAMES);
+        SURNAME = new ObjectIdentifier(new int[] { 2, 5, 4, 4 }, "SURNAME", //$NON-NLS-1$
+                RFC2459_NAMES);
+
+        T = new ObjectIdentifier(new int[] { 2, 5, 4, 12 }, "T", RFC2459_NAMES); //$NON-NLS-1$
+
+        UID = new ObjectIdentifier(
+                new int[] { 0, 9, 2342, 19200300, 100, 1, 1 }, "UID", //$NON-NLS-1$
+                RFC2253_NAMES);
+
+        //
+        // RFC1779
+        //
+        RFC1779_NAMES.put(CN.getName(), CN);
+        RFC1779_NAMES.put(L.getName(), L);
+        RFC1779_NAMES.put(ST.getName(), ST);
+        RFC1779_NAMES.put(O.getName(), O);
+        RFC1779_NAMES.put(OU.getName(), OU);
+        RFC1779_NAMES.put(C.getName(), C);
+        RFC1779_NAMES.put(STREET.getName(), STREET);
+
+        //
+        // RFC2253: includes all from RFC1779
+        //
+        RFC2253_NAMES.putAll(RFC1779_NAMES);
+
+        RFC2253_NAMES.put(DC.getName(), DC);
+        RFC2253_NAMES.put(UID.getName(), UID);
+
+        //
+        // RFC2459
+        //
+        RFC2459_NAMES.put(DNQ.getName(), DNQ);
+        RFC2459_NAMES.put(DNQUALIFIER.getName(), DNQUALIFIER);
+        RFC2459_NAMES.put(EMAILADDRESS.getName(), EMAILADDRESS);
+        RFC2459_NAMES.put(GENERATION.getName(), GENERATION);
+        RFC2459_NAMES.put(GIVENNAME.getName(), GIVENNAME);
+        RFC2459_NAMES.put(INITIALS.getName(), INITIALS);
+        RFC2459_NAMES.put(SERIALNUMBER.getName(), SERIALNUMBER);
+        RFC2459_NAMES.put(SURNAME.getName(), SURNAME);
+        RFC2459_NAMES.put(T.getName(), T);
+
+        //
+        // Init KNOWN_OIDS pool
+        //
+
+        // add from RFC2253 (includes RFC1779) 
+        Iterator it = RFC2253_NAMES.values().iterator();
+        while (it.hasNext()) {
+            addOID((ObjectIdentifier) it.next());
+        }
+
+        // add attributes from RFC2459
+        it = RFC2459_NAMES.values().iterator();
+        while (it.hasNext()) {
+            Object o = it.next();
+
+            //don't add DNQUALIFIER because it has the same oid as DNQ
+            if (!(o == DNQUALIFIER)) {
+                addOID((ObjectIdentifier) o);
+            }
+        }
+
+        //
+        // Init KNOWN_NAMES pool
+        //
+
+        KNOWN_NAMES.putAll(RFC2253_NAMES); // RFC2253 includes RFC1779
+        KNOWN_NAMES.putAll(RFC2459_NAMES);
+    }
+
+    //Attribute type
+    private final ObjectIdentifier oid;
+
+    //Attribute value
+    private AttributeValue value;
+
+    // for decoder only
+    private AttributeTypeAndValue(int[] oid, AttributeValue value)
+            throws IOException {
+
+        ObjectIdentifier thisOid = getOID(oid);
+        if (thisOid == null) {
+            thisOid = new ObjectIdentifier(oid);
+        }
+        this.oid = thisOid;
+        this.value = value;
+    }
+
+    /**
+     * Creates AttributeTypeAndValue with OID and AttributeValue. Parses OID
+     * string representation
+     * 
+     * @param sOid
+     *            string representation of OID
+     * @param value
+     *            attribute value
+     * @throws IOException
+     *             if OID can not be created from its string representation
+     */
+    public AttributeTypeAndValue(String sOid, AttributeValue value)
+            throws IOException {
+        if (sOid.charAt(0) >= '0' && sOid.charAt(0) <= '9') {
+
+            int[] array = org.apache.harmony.security.asn1.ObjectIdentifier
+                    .toIntArray(sOid);
+
+            ObjectIdentifier thisOid = getOID(array);
+            if (thisOid == null) {
+                thisOid = new ObjectIdentifier(array);
+            }
+            this.oid = thisOid;
+
+        } else {
+            this.oid = (ObjectIdentifier) KNOWN_NAMES.get(sOid.toUpperCase());
+            if (this.oid == null) {
+                throw new IOException(Messages.getString("security.178", sOid)); //$NON-NLS-1$
+            }
+        }
+        this.value = value;
+    }
+
+    /**
+     * Appends AttributeTypeAndValue string representation
+     * 
+     * @param attrFormat - format of DN
+     * @param buf - string buffer to be used
+     */
+    public void appendName(String attrFormat, StringBuffer buf) {
+
+        boolean hexFormat = false;
+        if (attrFormat == X500Principal.RFC1779) {
+            if (RFC1779_NAMES == oid.getGroup()) {
+                buf.append(oid.getName());
+            } else {
+                buf.append(oid.toOIDString());
+            }
+
+            buf.append('=');
+            if (value.escapedString == value.getHexString()) {
+                //FIXME all chars in upper case
+                buf.append(value.getHexString().toUpperCase());
+            } else if (value.escapedString.length() != value.rawString.length()) {
+                // was escaped
+                value.appendQEString(buf);
+            } else {
+                buf.append(value.escapedString);
+            }
+        } else {
+            Object group = oid.getGroup();
+            // RFC2253 includes names from RFC1779
+            if (RFC1779_NAMES == group || RFC2253_NAMES == group) {
+                buf.append(oid.getName());
+
+                if (attrFormat == X500Principal.CANONICAL) {
+                    // only PrintableString and UTF8String in string format
+                    // all others are output in hex format
+                    int tag = value.getTag();
+                    if (!ASN1StringType.UTF8STRING.checkTag(tag)
+                            && !ASN1StringType.PRINTABLESTRING.checkTag(tag)) {
+                        hexFormat = true;
+                    }
+                }
+
+            } else {
+                buf.append(oid.toString());
+                hexFormat = true;
+            }
+
+            buf.append('=');
+
+            if (hexFormat) {
+                buf.append(value.getHexString());
+            } else {
+                if (attrFormat == X500Principal.CANONICAL) {
+                    buf.append(value.makeCanonical());
+                } else {
+                    buf.append(value.escapedString);
+                }
+            }
+        }
+    }
+
+    /**
+     * Gets type of the AttributeTypeAndValue
+     * 
+     * @return ObjectIdentifier
+     */
+    public ObjectIdentifier getType() {
+        return oid;
+    }
+
+    /**
+     * According to RFC 3280 (http://www.ietf.org/rfc/rfc3280.txt) 
+     * X.501 AttributeTypeAndValue structure is defined as follows:
+     *  
+     *   AttributeTypeAndValue ::= SEQUENCE {
+     *      type     AttributeType,
+     *      value    AttributeValue }
+     *   
+     *    AttributeType ::= OBJECT IDENTIFIER
+     *  
+     *    AttributeValue ::= ANY DEFINED BY AttributeType
+     *    ...
+     *    DirectoryString ::= CHOICE {
+     *          teletexString           TeletexString (SIZE (1..MAX)),
+     *          printableString         PrintableString (SIZE (1..MAX)),
+     *          universalString         UniversalString (SIZE (1..MAX)),
+     *          utf8String              UTF8String (SIZE (1.. MAX)),
+     *          bmpString               BMPString (SIZE (1..MAX)) }
+     *  
+     */
+
+    public static ASN1Type AttributeValue = new ASN1Type(
+            ASN1Constants.TAG_PRINTABLESTRING) {
+
+        public boolean checkTag(int tag) {
+            return true;
+        }
+
+        public Object decode(BerInputStream in) throws IOException {
+
+            // FIXME what about constr???
+            String str = null;
+            if (DirectoryString.ASN1.checkTag(in.tag)) {
+                // has string representation
+                str = (String) DirectoryString.ASN1.decode(in);
+            } else {
+                // gets octets only
+                in.readContent();
+            }
+
+            byte[] bytesEncoded = new byte[in.getOffset() - in.getTagOffset()];
+            System.arraycopy(in.getBuffer(), in.getTagOffset(), bytesEncoded,
+                    0, bytesEncoded.length);
+
+            return new AttributeValue(str, bytesEncoded, in.tag);
+        }
+
+        public Object getDecodedObject(BerInputStream in) throws IOException {
+            // stub to avoid wrong decoder usage
+            throw new RuntimeException(Messages.getString("security.179")); //$NON-NLS-1$
+        }
+
+        //
+        // Encode
+        //
+        public void encodeASN(BerOutputStream out) {
+
+            AttributeValue av = (AttributeValue) out.content;
+
+            if (av.encoded != null) {
+                out.content = av.encoded;
+                out.encodeANY();
+            } else {
+                out.encodeTag(av.getTag());
+                out.content = av.bytes;
+                out.encodeString();
+            }
+        }
+
+        public void setEncodingContent(BerOutputStream out) {
+            
+            AttributeValue av = (AttributeValue) out.content;
+
+            if (av.encoded != null) {
+                out.length = av.encoded.length;
+            } else {
+
+                if (av.getTag() == ASN1Constants.TAG_UTF8STRING) {
+
+                    out.content = av.rawString;
+
+                    ASN1StringType.UTF8STRING.setEncodingContent(out);
+
+                    av.bytes = (byte[]) out.content;
+                    out.content = av;
+                } else {
+                    av.bytes = av.rawString.getBytes();
+                    out.length = av.bytes.length;
+                }
+            }
+        }
+
+        public void encodeContent(BerOutputStream out) {
+            // stub to avoid wrong encoder usage
+            throw new RuntimeException(Messages.getString("security.17A")); //$NON-NLS-1$
+        }
+
+        public int getEncodedLength(BerOutputStream out) { //FIXME name
+
+            AttributeValue av = (AttributeValue) out.content;
+
+            if (av.encoded != null) {
+                return out.length;
+            } else {
+                return super.getEncodedLength(out);
+            }
+        }
+    };
+
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
+            ASN1Oid.getInstance(), AttributeValue }) {
+
+        protected Object getDecodedObject(BerInputStream in) throws IOException {
+            Object[] values = (Object[]) in.content;
+            return new AttributeTypeAndValue((int[]) values[0],
+                    (AttributeValue) values[1]);
+        }
+
+        protected void getValues(Object object, Object[] values) {
+            AttributeTypeAndValue atav = (AttributeTypeAndValue) object;
+
+            values[0] = atav.oid.getOid();
+            values[1] = atav.value;
+        }
+    };
+
+    // returns known OID or null
+    private static ObjectIdentifier getOID(int[] oid) {
+
+        int index = hashIntArray(oid) % CAPACITY;
+
+        // look for OID in the pool 
+        ObjectIdentifier[] list = KNOWN_OIDS[index];
+        for (int i = 0; list[i] != null; i++) {
+            if (Arrays.equals(oid, list[i].getOid())) {
+                return list[i];
+            }
+        }
+        return null;
+    }
+
+    // adds known OID to pool
+    // for static AttributeTypeAndValue initialization only
+    private static void addOID(ObjectIdentifier oid) {
+
+        int[] newOid = oid.getOid();
+        int index = hashIntArray(newOid) % CAPACITY;
+
+        // look for OID in the pool 
+        ObjectIdentifier[] list = KNOWN_OIDS[index];
+        int i = 0;
+        for (; list[i] != null; i++) {
+
+            // check wrong static initialization: no duplicate OIDs
+            if (Arrays.equals(newOid, list[i].getOid())) {
+                throw new Error(Messages.getString("security.17B", //$NON-NLS-1$
+                                oid.getName(), list[i].getName()));
+            }
+        }
+
+        // check : to avoid NPE
+        if (i == (CAPACITY - 1)) {
+            throw new Error(Messages.getString("security.17C")); //$NON-NLS-1$
+        }
+        list[i] = oid;
+    }
+
+    // returns hash for array of integers
+    private static int hashIntArray(int[] oid) {
+        int intHash = 0;
+        for (int i = 0; i < oid.length && i < 4; i++) {
+            intHash += oid[i] << (8 * i); //TODO what about to find better one?
+        }
+        return intHash & 0x7FFFFFFF; // only positive
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x501/AttributeTypeAndValueComparator.java b/libcore/security/src/main/java/org/apache/harmony/security/x501/AttributeTypeAndValueComparator.java
new file mode 100644
index 0000000..8844035
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x501/AttributeTypeAndValueComparator.java
@@ -0,0 +1,108 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Esin
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x501;
+
+import java.util.Comparator;
+
+import org.apache.harmony.security.utils.ObjectIdentifier;
+
+/**
+ * AttributeTypeAndValue comparator
+ * 
+ */
+public class AttributeTypeAndValueComparator implements Comparator {
+
+    /**
+     * compares two AttributeTypeAndValues
+     * 
+     * @param obj1
+     *            first AttributeTypeAndValue
+     * @param obj2
+     *            second AttributeTypeAndValue
+     * @return -1 of first AttributeTypeAndValue "less" than second
+     *         AttributeTypeAndValue 1 otherwise, 0 if they are equal
+     */
+    public int compare(Object obj1, Object obj2) {
+        if (obj1 == obj2) {
+            return 0;
+        }
+
+        AttributeTypeAndValue atav1 = (AttributeTypeAndValue) obj1;
+        AttributeTypeAndValue atav2 = (AttributeTypeAndValue) obj2;
+        String kw1 = atav1.getType().getName();
+        String kw2 = atav2.getType().getName();
+        if (kw1 != null && kw2 == null) {
+            return -1;
+        }
+        if (kw1 == null && kw2 != null) {
+            return 1;
+        }
+        if (kw1 != null && kw2 != null) {
+            return kw1.compareTo(kw2);
+        }
+
+        return compateOids(atav1.getType(), atav2.getType());
+    }
+
+    /**
+     * @return false
+     */
+    public boolean equals(Object obj) {
+        return false;
+    }
+
+    /**
+     * compares two Object identifiers
+     * 
+     * @param oid1
+     *            first OID
+     * @param oid2
+     *            second OID
+     * @return -1 of first OID "less" than second OID 1 otherwise, 0 if they are
+     *         equal
+     */
+    private static int compateOids(ObjectIdentifier oid1, ObjectIdentifier oid2) {
+        if (oid1 == oid2) {
+            return 0;
+        }
+
+        int[] ioid1 = oid1.getOid();
+        int[] ioid2 = oid2.getOid();
+        int min = ioid1.length < ioid2.length ? ioid1.length : ioid2.length;
+        for (int i = 0; i < min; ++i) {
+            if (ioid1[i] < ioid2[i]) {
+                return -1;
+            }
+            if (ioid1[i] > ioid2[i]) {
+                return 1;
+            }
+            if ((i + 1) == ioid1.length && (i + 1) < ioid2.length) {
+                return -1;
+            }
+            if ((i + 1) < ioid1.length && (i + 1) == ioid2.length) {
+                return 1;
+            }
+        }
+        return 0;
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x501/AttributeValue.java b/libcore/security/src/main/java/org/apache/harmony/security/x501/AttributeValue.java
new file mode 100644
index 0000000..51f9725
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x501/AttributeValue.java
@@ -0,0 +1,272 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Esin
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x501;
+
+import java.io.IOException;
+
+import org.apache.harmony.security.asn1.ASN1StringType;
+import org.apache.harmony.security.asn1.DerInputStream;
+import org.apache.harmony.security.x509.Utils;
+
+
+/**
+ * X.501 Attribute Value
+ */
+public class AttributeValue {
+
+    public final boolean wasEncoded;
+
+    public String escapedString;
+
+    private String hexString;
+
+    private int tag = -1;
+
+    public byte[] encoded;
+
+    public byte[] bytes; //FIXME remove??? bytes to be encoded
+
+    public boolean hasQE; // raw string contains '"' or '\'
+
+    public AttributeValue(String parsedString, boolean hasQorE) {
+
+        wasEncoded = false;
+
+        this.hasQE = hasQorE;
+
+        this.rawString = parsedString;
+        this.escapedString = makeEscaped(rawString);
+    }
+
+    public AttributeValue(String hexString, byte[] encoded) {
+
+        wasEncoded = true;
+
+        this.hexString = hexString;
+        this.encoded = encoded;
+
+        try {
+            DerInputStream in = new DerInputStream(encoded);
+
+            tag = in.tag;
+
+            if (DirectoryString.ASN1.checkTag(tag)) {
+                // has string representation
+                this.rawString = (String) DirectoryString.ASN1.decode(in);
+                this.escapedString = makeEscaped(rawString);
+            } else {
+                this.rawString = hexString;
+                this.escapedString = hexString;
+            }
+        } catch (IOException e) {
+            IllegalArgumentException iae = new IllegalArgumentException(); //FIXME message
+            iae.initCause(e);
+            throw iae;
+        }
+    }
+
+    public String rawString;
+
+    public AttributeValue(String rawString, byte[] encoded, int tag) {
+
+        wasEncoded = true;
+
+        this.encoded = encoded;
+        this.tag = tag;
+
+        if (rawString == null) {
+            this.rawString = getHexString();
+            this.escapedString = hexString;
+        } else {
+            this.rawString = rawString;
+            this.escapedString = makeEscaped(rawString);
+        }
+    }
+
+    public int getTag() {
+        if (tag == -1) {
+            if (Utils.isPrintableString(rawString)) {
+                tag = ASN1StringType.PRINTABLESTRING.id;
+            } else {
+                tag = ASN1StringType.UTF8STRING.id;
+            }
+        }
+        return tag;
+    }
+
+    public String getHexString() {
+        if (hexString == null) {
+
+            if (!wasEncoded) {
+                //FIXME optimize me: what about reusable OutputStream???
+                if (Utils.isPrintableString(rawString)) {
+                    encoded = ASN1StringType.PRINTABLESTRING.encode(rawString);
+                } else {
+                    encoded = ASN1StringType.UTF8STRING.encode(rawString);
+                }
+            }
+
+            StringBuffer buf = new StringBuffer(encoded.length * 2 + 1);
+            buf.append('#');
+
+            for (int i = 0, c; i < encoded.length; i++) {
+                c = (encoded[i] >> 4) & 0x0F;
+                if (c < 10) {
+                    buf.append((char) (c + 48));
+                } else {
+                    buf.append((char) (c + 87));
+                }
+
+                c = encoded[i] & 0x0F;
+                if (c < 10) {
+                    buf.append((char) (c + 48));
+                } else {
+                    buf.append((char) (c + 87));
+                }
+            }
+            hexString = buf.toString();
+        }
+        return hexString;
+    }
+
+    public void appendQEString(StringBuffer buf) {
+        buf.append('"');
+        if (hasQE) {
+            char c;
+            for (int i = 0; i < rawString.length(); i++) {
+                c = rawString.charAt(i);
+                if (c == '"' || c == '\\') {
+                    buf.append('\\');
+                }
+                buf.append(c);
+            }
+        } else {
+            buf.append(rawString);
+        }
+        buf.append('"');
+    }
+
+    //
+    // Escapes:
+    // 1) chars ",", "+", """, "\", "<", ">", ";" (RFC 2253) 
+    // 2) chars "#", "=" (required by RFC 1779)
+    // 3) a space char at the beginning or end
+    // 4) according to the requirement to be RFC 1779 compatible:
+    //    '#' char is escaped in any position
+    //
+    private String makeEscaped(String name) {
+
+        int length = name.length();
+        if (length == 0) {
+            return name;
+        }
+        StringBuffer buf = new StringBuffer(length * 2);
+
+        for (int index = 0; index < length; index++) {
+
+            char ch = name.charAt(index);
+
+            switch (ch) {
+
+            case ' ':
+                if (index == 0 || index == (length - 1)) {
+                    // escape first or last space 
+                    buf.append('\\');
+                }
+                buf.append(' ');
+                break;
+
+            case '"':
+            case '\\':
+                hasQE = true;
+
+            case ',':
+            case '+':
+            case '<':
+            case '>':
+            case ';':
+            case '#': // required by RFC 1779
+            case '=': // required by RFC 1779
+                buf.append('\\');
+
+            default:
+                buf.append(ch);
+            }
+        }
+
+        return buf.toString();
+    }
+
+    public String makeCanonical() {
+
+        int length = rawString.length();
+        if (length == 0) {
+            return rawString;
+        }
+        StringBuffer buf = new StringBuffer(length * 2);
+
+        int index = 0;
+        if (rawString.charAt(0) == '#') {
+            buf.append('\\');
+            buf.append('#');
+            index++;
+        }
+
+        int bufLength;
+        for (; index < length; index++) {
+
+            char ch = rawString.charAt(index);
+
+            switch (ch) {
+
+            case ' ':
+                bufLength = buf.length();
+                if (bufLength == 0 || buf.charAt(bufLength - 1) == ' ') {
+                    break;
+                }
+                buf.append(' ');
+                break;
+
+            case '"':
+            case '\\':
+            case ',':
+            case '+':
+            case '<':
+            case '>':
+            case ';':
+                buf.append('\\');
+
+            default:
+                buf.append(ch);
+            }
+        }
+
+        //remove trailing spaces
+        for (bufLength = buf.length() - 1; bufLength > -1
+                && buf.charAt(bufLength) == ' '; bufLength--) {
+        }
+        buf.setLength(bufLength + 1);
+
+        return buf.toString();
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x501/Attributes.java b/libcore/security/src/main/java/org/apache/harmony/security/x501/Attributes.java
new file mode 100644
index 0000000..38c6f4f
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x501/Attributes.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+/**
+* @author Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x501;
+
+import org.apache.harmony.security.asn1.ASN1OpenType;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1SetOf;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.InformationObjectSet;
+
+
+/**
+ * X.501 Attributes
+ * 
+ * This is a draft class for Module InformationFramework (X.501).
+ * 
+ * @see <a href="http://www.itu.int/ITU-T/asn1/database/itu-t/x/x501/2001/InformationFramework.html">X.501</a>
+ */
+
+public class Attributes {
+
+    
+    /**
+     * The class corresponds to following ASN.1 type:
+     * 
+     * Attribute ::= SEQUENCE {
+     *     type  AttributeType,
+     *     values SET SIZE (0..MAX) OF AttributeValue }
+     * 
+     * AttributeType ::= OBJECT IDENTIFIER
+     * 
+     * AttributeValue ::= ANY DEFINED BY AttributeType
+     * 
+     */
+    public static ASN1Sequence getASN1(InformationObjectSet set) {
+        ASN1OpenType.Id id = new ASN1OpenType.Id();
+        ASN1OpenType any = new ASN1OpenType(id, set);
+
+        return new ASN1Sequence(new ASN1Type[] { id, new ASN1SetOf(any) });
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x501/DirectoryString.java b/libcore/security/src/main/java/org/apache/harmony/security/x501/DirectoryString.java
new file mode 100644
index 0000000..aafb8b5
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x501/DirectoryString.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x501;
+
+import org.apache.harmony.security.asn1.ASN1Choice;
+import org.apache.harmony.security.asn1.ASN1StringType;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with the DirectoryString structure
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *
+ * <pre>
+ *   DirectoryString ::= CHOICE {
+ *        teletexString             TeletexString   (SIZE (1..MAX)),
+ *        printableString           PrintableString (SIZE (1..MAX)),
+ *        universalString           UniversalString (SIZE (1..MAX)),
+ *        utf8String              UTF8String      (SIZE (1..MAX)),
+ *        bmpString               BMPString       (SIZE (1..MAX)) 
+ *   }
+ * </pre>
+ */
+public class DirectoryString {
+    
+    public static final ASN1Choice ASN1 = new ASN1Choice(new ASN1Type[] {
+           ASN1StringType.TELETEXSTRING,
+           ASN1StringType.PRINTABLESTRING,
+           ASN1StringType.UNIVERSALSTRING,
+           ASN1StringType.UTF8STRING,
+           ASN1StringType.BMPSTRING }) {
+
+        public int getIndex(java.lang.Object object) {
+            return 1; // always code as ASN1 printableString
+            //return 4; // always code as ASN1 utf8String
+        }
+
+        public Object getObjectToEncode(Object object) {
+            return /*(String)*/ object;
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x501/Name.java b/libcore/security/src/main/java/org/apache/harmony/security/x501/Name.java
new file mode 100644
index 0000000..836342e
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x501/Name.java
@@ -0,0 +1,265 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Esin
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x501;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.asn1.ASN1SequenceOf;
+import org.apache.harmony.security.asn1.ASN1SetOf;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.asn1.DerInputStream;
+import org.apache.harmony.security.internal.nls.Messages;
+import org.apache.harmony.security.x509.DNParser;
+
+
+/**
+ * X.501 Name
+ */
+public class Name {
+
+    //ASN.1 DER encoding of Name
+    private volatile byte[] encoded;
+
+    // RFC1779 string
+    private String rfc1779String;
+
+    // RFC2253 string
+    private String rfc2253String;
+
+    //CANONICAL string
+    private String canonicalString;
+
+    //Collection of RDNs
+    private List rdn;
+
+    /**
+     * Creates new <code>Name</code> instance from its DER encoding
+     * 
+     * @param encoding - ASN.1 DER encoding
+     * @throws IOException - if encoding is wrong
+     */
+    public Name(byte[] encoding) throws IOException {
+
+        DerInputStream in = new DerInputStream(encoding);
+
+        if (in.getEndOffset() != encoding.length) {
+            throw new IOException(Messages.getString("security.111")); //$NON-NLS-1$
+        }
+
+        ASN1.decode(in);
+
+        this.rdn = (List) in.content;
+    }
+
+    /**
+     * Creates new <code>Name</code> instance
+     * 
+     * @param name - Name as String
+     * @throws IOException - if string is wrong
+     */
+    public Name(String name) throws IOException {
+        rdn = new DNParser(name).parse();
+    }
+
+    // Creates Name instance
+    private Name(List rdn) {
+        this.rdn = rdn;
+    }
+
+    /**
+     * Returns <code>X500Principal</code> instance corresponding to this
+     * <code>Name</code> instance
+     * 
+     * @return equivalent X500Principal object
+     */
+    public X500Principal getX500Principal(){
+        return new X500Principal(getName0(X500Principal.RFC2253));
+    }
+    
+    /**
+     * Returns Relative Distinguished Name as <code>String</code> according
+     * the format requested
+     * 
+     * @param format
+     *            Name format requested
+     * @return Relative Distinguished Name as <code>String</code> according
+     *         the format requested
+     */
+    public String getName(String format) {
+
+        //
+        // check X500Principal constants first
+        //
+        if (format == X500Principal.RFC1779) {
+
+            if (rfc1779String == null) {
+                rfc1779String = getName0(format);
+            }
+            return rfc1779String;
+
+        } else if (format == X500Principal.RFC2253) {
+
+            if (rfc2253String == null) {
+                rfc2253String = getName0(format);
+            }
+            return rfc2253String;
+
+        } else if (format == X500Principal.CANONICAL) {
+
+            if (canonicalString == null) {
+                canonicalString = getName0(format);
+            }
+            return canonicalString;
+
+        }
+        //
+        // compare ignore case
+        //
+        else if (X500Principal.RFC1779.equalsIgnoreCase(format)) {
+
+            if (rfc1779String == null) {
+                rfc1779String = getName0(X500Principal.RFC1779);
+            }
+            return rfc1779String;
+
+        } else if (X500Principal.RFC2253.equalsIgnoreCase(format)) {
+
+            if (rfc2253String == null) {
+                rfc2253String = getName0(X500Principal.RFC2253);
+            }
+            return rfc2253String;
+
+        } else if (X500Principal.CANONICAL.equalsIgnoreCase(format)) {
+
+            if (canonicalString == null) {
+                canonicalString = getName0(X500Principal.CANONICAL);
+            }
+            return canonicalString;
+
+        } else {
+            throw new IllegalArgumentException(Messages.getString("security.177", format)); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Returns Relative Distinguished Name as <code>String</code> according
+     * the format requested, format is int value
+     * 
+     * @param format
+     *            Name format requested
+     * @return Relative Distinguished Name as <code>String</code> according
+     *         the format requested
+     */
+    private String getName0(String format) {
+        
+        StringBuffer name = new StringBuffer();
+
+        // starting with the last element and moving to the first.
+        for (int i = rdn.size() - 1; i >= 0; i--) {
+            List atavList = (List) rdn.get(i);
+
+            if (X500Principal.CANONICAL == format) {
+                List sortedList = new LinkedList(atavList);
+                Collections.sort(sortedList,
+                        new AttributeTypeAndValueComparator());
+                atavList = sortedList;
+            }
+
+            // Relative Distinguished Name to string
+            Iterator it = atavList.iterator();
+            while (it.hasNext()) {
+                AttributeTypeAndValue _ava = (AttributeTypeAndValue) it.next();
+                _ava.appendName(format, name);
+                if (it.hasNext()) {
+                    // multi-valued RDN
+                    if (X500Principal.RFC1779 == format) {
+                        name.append(" + "); //$NON-NLS-1$
+                    } else {
+                        name.append('+');
+                    }
+                }
+            }
+
+            if (i != 0) {
+                name.append(',');
+                if (format == X500Principal.RFC1779) {
+                    name.append(' ');
+                }
+            }
+        }
+
+        String sName = name.toString();
+        if (format == X500Principal.CANONICAL) {
+            sName = sName.toLowerCase(Locale.US);
+        }
+        return sName;
+    }
+
+    /**
+     * Gets encoded form of DN
+     * 
+     * @return return encoding, no copying is performed
+     */
+    public byte[] getEncoded() {
+        if (encoded == null) {
+            encoded = ASN1.encode(this);
+        }
+        return encoded;
+    }
+
+    /**
+     * According to RFC 3280 (http://www.ietf.org/rfc/rfc3280.txt) 
+     * X.501 Name structure is defined as follows:
+     * 
+     * Name ::= CHOICE {
+     *     RDNSequence }
+     *  
+     * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+     *  
+     * RelativeDistinguishedName ::=
+     *     SET OF AttributeTypeAndValue
+     * 
+     */
+
+    public static final ASN1SetOf ASN1_RDN = new ASN1SetOf(
+            AttributeTypeAndValue.ASN1);
+
+    public static final ASN1SequenceOf ASN1 = new ASN1SequenceOf(ASN1_RDN) {
+
+        public Object getDecodedObject(BerInputStream in) {
+            return new Name((List) in.content);
+        }
+
+        public Collection getValues(Object object) {
+            return ((Name) object).rdn; //FIXME what about get method?
+        }
+    };
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/AccessDescription.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/AccessDescription.java
new file mode 100644
index 0000000..bc8fd28
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/AccessDescription.java
@@ -0,0 +1,121 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.security.x509;
+
+import org.apache.harmony.security.asn1.ASN1Oid;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.asn1.ObjectIdentifier;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work
+ * with the AccessDescription which is a part of X.509 framework
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *  
+ *  AccessDescription  ::=  SEQUENCE {
+ *      accessMethod          OBJECT IDENTIFIER,
+ *      accessLocation        GeneralName  }
+ * 
+ */
+public class AccessDescription {
+    
+    // the value of access method
+    private final String accessMethod;
+    
+    // the value of accessLocation
+    private final GeneralName accessLocation;
+    
+    private byte [] encoding;
+    
+    public AccessDescription(String accessMethod, GeneralName accessLocation) {
+        this.accessMethod = accessMethod;
+        this.accessLocation = accessLocation;
+    }
+    
+    private AccessDescription(String accessMethod, GeneralName accessLocation,
+            byte[] encoding) {
+        this.accessMethod = accessMethod;
+        this.accessLocation = accessLocation;
+        this.encoding = encoding;
+    }
+
+    /**
+     * Returns ASN.1 encoded form of this X.509 AccessDescription.
+     * @return a byte array containing ASN.1 encoded form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    public String toString() {
+        StringBuffer res = new StringBuffer();
+        res.append("\n-- AccessDescription:"); //$NON-NLS-1$
+        res.append("\naccessMethod:  "); //$NON-NLS-1$
+        res.append(accessMethod);
+        res.append("\naccessLocation:  "); //$NON-NLS-1$
+        res.append(accessLocation);
+        res.append("\n-- AccessDescription END\n"); //$NON-NLS-1$
+        return res.toString();
+    }
+
+    /**
+     * @return Returns the accessLocation.
+     */
+    public GeneralName getAccessLocation() {
+        return accessLocation;
+    }
+
+    /**
+     * @return Returns the accessMethod.
+     */
+    public String getAccessMethod() {
+        return accessMethod;
+    }
+    
+    /**
+     * Custom AccessDescription DER encoder/decoder
+     */
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
+            ASN1Oid.getInstance(), 
+            GeneralName.ASN1 }) {
+
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+            return new AccessDescription(
+                    ObjectIdentifier.toString((int[]) values[0]), 
+                    (GeneralName) values[1], in.getEncoded());
+        }
+
+        protected void getValues(Object object, Object[] values) {
+
+            AccessDescription ad = (AccessDescription) object;
+
+            values[0] = ObjectIdentifier.toIntArray(ad.accessMethod);
+            values[1] = ad.accessLocation;
+        }
+    };
+
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/AlgorithmIdentifier.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/AlgorithmIdentifier.java
new file mode 100644
index 0000000..70dba99
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/AlgorithmIdentifier.java
@@ -0,0 +1,185 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import java.util.Arrays;
+
+import org.apache.harmony.security.asn1.ASN1Any;
+import org.apache.harmony.security.asn1.ASN1Oid;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.asn1.ObjectIdentifier;
+import org.apache.harmony.security.utils.AlgNameMapper;
+
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work
+ * with the Algorithm Identifier which is a part of X.509 certificate
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *
+ * <pre>
+ *  AlgorithmIdentifier ::= SEQUENCE {
+ *      algorithm OBJECT IDENTIFIER,
+ *      parameters ANY DEFINED BY algorithm OPTIONAL 
+ *  }
+ * </pre>
+ */
+public class AlgorithmIdentifier {
+
+    // the value of algorithm field
+    private String algorithm;
+    // the name of the algorithm
+    private String algorithmName;
+    // the value of parameters field
+    private byte[] parameters;
+    // the encoding of AlgorithmIdentifier value
+    private byte[] encoding;
+    
+    /**
+     * TODO
+     * @param   algorithm:  String
+     */
+    public AlgorithmIdentifier(String algorithm) {
+        this(algorithm, null, null);
+    }
+    
+    /**
+     * TODO
+     * @param   algorithm:  String
+     * @param   parameters: byte[]
+     */
+    public AlgorithmIdentifier(String algorithm, byte[] parameters) {
+        this(algorithm, parameters, null);
+    }
+
+    // 
+    // TODO
+    // @param   algorithm:  String
+    // @param   parameters: byte[]
+    // @param   encoding:   byte[]
+    // 
+    private AlgorithmIdentifier(String algorithm, byte[] parameters, 
+                                byte[] encoding) {
+        this.algorithm = algorithm;
+        this.parameters = parameters;
+        this.encoding = encoding;
+    }
+        
+    /**
+     * Returns the value of algorithm field of the structure.
+     * @return  algorithm
+     */
+    public String getAlgorithm() {
+        return algorithm;
+    }
+
+    /**
+     * Returns the name of the algorithm corresponding to
+     * its OID. If there is no the such correspondence,
+     * algorithm OID is returned.
+     * @return  algorithm
+     */
+    public String getAlgorithmName() {
+        if (algorithmName == null) {
+            algorithmName = AlgNameMapper.map2AlgName(algorithm);
+            if (algorithmName == null) {
+                algorithmName = algorithm;
+            }
+        }
+        return algorithmName;
+    }
+
+    /**
+     * Returns the value of parameters field of the structure.
+     * @return  parameters
+     */
+    public byte[] getParameters() {
+        return parameters;
+    }
+    
+    /**
+     * Returns ASN.1 encoded form of this X.509 AlgorithmIdentifier value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+    
+    public boolean equals(Object ai) {
+        if (!(ai instanceof AlgorithmIdentifier)) {
+            return false;
+        }
+        AlgorithmIdentifier algid = (AlgorithmIdentifier) ai;
+        return (algorithm.equals(algid.algorithm))
+            && ((parameters == null)
+                    ? algid.parameters == null
+                    : Arrays.equals(parameters, algid.parameters));
+    }
+    
+    /**
+     * Places the string representation into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer) {
+        buffer.append(getAlgorithmName());
+        if (parameters == null) {
+            buffer.append(", no params, "); //$NON-NLS-1$
+        } else {
+            buffer.append(", params unparsed, "); //$NON-NLS-1$
+        }
+        buffer.append("OID = "); //$NON-NLS-1$
+        buffer.append(getAlgorithm());
+    }
+
+    /**
+     * Custom AlgorithmIdentifier DER encoder/decoder
+     */
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
+            ASN1Oid.getInstance(), ASN1Any.getInstance() }) {
+        {
+            setOptional(1); // parameters are optional
+        }
+
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+            return new AlgorithmIdentifier(ObjectIdentifier
+                    .toString((int[]) values[0]), (byte[]) values[1]);
+        }
+
+        protected void getValues(Object object, Object[] values) {
+
+            AlgorithmIdentifier aID = (AlgorithmIdentifier) object;
+
+            values[0] = ObjectIdentifier.toIntArray(aID.getAlgorithm());
+            values[1] = aID.getParameters();
+        }
+    };
+
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/AlternativeName.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/AlternativeName.java
new file mode 100644
index 0000000..fd055c7
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/AlternativeName.java
@@ -0,0 +1,95 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * This class implements the values of Subject Alternative Name
+ * (OID is 2.5.29.17) and Issuer Alternative Name extensions
+ * (OID is 2.5.29.18).<br>
+ * For more information about these extensions see RFC 3280
+ * at http://www.ietf.org/rfc/rfc3280.txt
+ */
+public class AlternativeName extends ExtensionValue {
+
+    // constants indicating which alternative name is presented
+    // by this object
+    public static final boolean ISSUER = false;
+    public static final boolean SUBJECT = true;
+
+    // indicating which alternative name is presented by this object
+    private boolean which;
+    // the alternative names
+    private GeneralNames alternativeNames;
+
+    /**
+     * Creates the extension object for given alternative names.
+     * @param which specifies which alternative names are given
+     * (Subject's or Issuer's)
+     */
+    public AlternativeName(boolean which, GeneralNames alternativeNames) {
+        this.which = which;
+        this.alternativeNames = alternativeNames;
+    }
+
+    /**
+     * Creates the extension object on the base of its encoded form.
+     * @param which specifies which alternative names are given
+     * (Subject's or Issuer's)
+     */
+    public AlternativeName(boolean which, byte[] encoding) throws IOException {
+        super(encoding);
+        this.which = which;
+        this.alternativeNames =
+            (GeneralNames) GeneralNames.ASN1.decode(encoding);
+    }
+
+    /**
+     * Returns the list of alternative names.
+     * The list is in the collection of pairs:<br>
+     * [Integer (tag of GeneralName), Object (name value)]
+     */
+    public List getAlternativeNames() {
+        return alternativeNames.getPairsList();
+    }
+
+    /**
+     * Returns ASN.1 encoded form of this X.509 AlternativeName value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = GeneralNames.ASN1.encode(alternativeNames);
+        }
+        return encoding;
+    }
+
+    /**
+     * Places the string representation of extension value
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        buffer.append(prefix).append((which) ? "Subject" : "Issuer") //$NON-NLS-1$ //$NON-NLS-2$
+            .append(" Alternative Names [\n"); //$NON-NLS-1$
+        alternativeNames.dumpValue(buffer, prefix + "  "); //$NON-NLS-1$
+        buffer.append(prefix).append("]\n"); //$NON-NLS-1$
+    }
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/AuthorityKeyIdentifier.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/AuthorityKeyIdentifier.java
new file mode 100644
index 0000000..1cf9c3e
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/AuthorityKeyIdentifier.java
@@ -0,0 +1,143 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+import org.apache.harmony.security.asn1.ASN1Implicit;
+import org.apache.harmony.security.asn1.ASN1Integer;
+import org.apache.harmony.security.asn1.ASN1OctetString;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.utils.Array;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work
+ * with Authority Key Identifier Extension (OID = 2.5.29.35). 
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *
+ * <pre>
+ *   id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 35 }
+ *
+ *   AuthorityKeyIdentifier ::= SEQUENCE {
+ *      keyIdentifier             [0] KeyIdentifier           OPTIONAL,
+ *      authorityCertIssuer       [1] GeneralNames            OPTIONAL,
+ *      authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL  }
+ *
+ *   KeyIdentifier ::= OCTET STRING
+ * </pre>
+ */
+public class AuthorityKeyIdentifier extends ExtensionValue {
+   
+    private final byte[] keyIdentifier;
+    private final GeneralNames authorityCertIssuer;
+    private final BigInteger authorityCertSerialNumber;
+    
+    public AuthorityKeyIdentifier(byte[] keyIdentifier, 
+            GeneralNames authorityCertIssuer, 
+            BigInteger authorityCertSerialNumber) {
+        this.keyIdentifier = keyIdentifier;
+        this.authorityCertIssuer = authorityCertIssuer;
+        this.authorityCertSerialNumber = authorityCertSerialNumber;
+    }
+    
+    public static AuthorityKeyIdentifier decode(byte[] encoding) 
+            throws IOException {
+        AuthorityKeyIdentifier aki =
+            (AuthorityKeyIdentifier) ASN1.decode(encoding);
+        aki.encoding = encoding;
+        return aki;
+    } 
+
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    /**
+     * Places the string representation of extension value 
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        buffer.append(prefix).append("AuthorityKeyIdentifier [\n"); //$NON-NLS-1$
+        if (keyIdentifier != null) {
+            buffer.append(prefix).append("  keyIdentifier:\n"); //$NON-NLS-1$
+            buffer.append(Array.toString(keyIdentifier, prefix + "    ")); //$NON-NLS-1$
+        }
+        if (authorityCertIssuer != null) {
+            buffer.append(prefix).append("  authorityCertIssuer: [\n"); //$NON-NLS-1$
+            authorityCertIssuer.dumpValue(buffer, prefix + "    "); //$NON-NLS-1$
+            buffer.append(prefix).append("  ]\n"); //$NON-NLS-1$
+        }
+        if (authorityCertSerialNumber != null) {
+            buffer.append(prefix).append("  authorityCertSerialNumber: ") //$NON-NLS-1$
+                .append(authorityCertSerialNumber).append('\n');
+        }
+        buffer.append(prefix).append("]\n"); //$NON-NLS-1$
+    }
+
+    public static ASN1Type ASN1 = new ASN1Sequence(
+            new ASN1Type[] {
+                new ASN1Implicit(0, ASN1OctetString.getInstance()),
+                new ASN1Implicit(1, GeneralNames.ASN1),
+                new ASN1Implicit(2, ASN1Integer.getInstance()),
+            }) {
+        {
+            setOptional(0);
+            setOptional(1);
+            setOptional(2);
+        }
+
+        protected Object getDecodedObject(BerInputStream in) throws IOException {
+            Object[] values = (Object[]) in.content;
+
+            byte[] enc = (byte[]) values[2];
+            BigInteger authorityCertSerialNumber = null;
+            if (enc != null) {
+                authorityCertSerialNumber = new BigInteger(enc);
+            }
+
+            return new AuthorityKeyIdentifier((byte[]) values[0],
+                    (GeneralNames) values[1], authorityCertSerialNumber);
+        }
+
+        protected void getValues(Object object, Object[] values) {
+
+            AuthorityKeyIdentifier akid = (AuthorityKeyIdentifier) object;
+
+            values[0] = akid.keyIdentifier;
+            values[1] = akid.authorityCertIssuer;
+            if (akid.authorityCertSerialNumber != null) {
+                values[2] = akid.authorityCertSerialNumber.toByteArray();
+            }
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/BasicConstraints.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/BasicConstraints.java
new file mode 100644
index 0000000..10b3156
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/BasicConstraints.java
@@ -0,0 +1,127 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import org.apache.harmony.security.asn1.ASN1Boolean;
+import org.apache.harmony.security.asn1.ASN1Integer;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.BerInputStream;
+
+/**
+ * Basic Constraints Extension (OID == 2.5.29.19).
+ *
+ * The ASN.1 definition for Basic Constraints Extension is:
+ *
+ * <pre>
+ *   id-ce-basicConstraints OBJECT IDENTIFIER ::=  { id-ce 19 }
+ *
+ *   BasicConstraints ::= SEQUENCE {
+ *        cA                      BOOLEAN DEFAULT FALSE,
+ *        pathLenConstraint       INTEGER (0..MAX) OPTIONAL
+ *   }
+ * </pre>
+ * (as specified in RFC 3280)
+ */
+public class BasicConstraints extends ExtensionValue {
+
+    // is CA
+    private boolean cA = false;
+    // path len constraint
+    private int pathLenConstraint = Integer.MAX_VALUE;
+
+    // Constructor for creating the extension without
+    // encoding provided
+    /**
+     * Creates the extension object on the base of the values of
+     * fields of the structure..
+     */
+    public BasicConstraints(boolean cA, int pathLenConstraint) {
+        this.cA = cA;
+        this.pathLenConstraint = pathLenConstraint;
+    }
+
+    /**
+     * Creates the extension object on the base of its encoded form.
+     */
+    public BasicConstraints(byte[] encoding) throws IOException {
+        super(encoding);
+        Object[] values = (Object[]) ASN1.decode(encoding);
+        cA = ((Boolean) values[0]).booleanValue();
+        if (values[1] != null) {
+            pathLenConstraint = new BigInteger((byte[]) values[1]).intValue();
+        }
+    }
+
+    public boolean getCA() {
+        return cA;
+    }
+
+    public int getPathLenConstraint() {
+        return pathLenConstraint;
+    }
+
+    /**
+     * Returns the encoded form of the object.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(
+                    new Object[] {Boolean.valueOf(cA),
+                        BigInteger.valueOf(pathLenConstraint)});
+        }
+        return encoding;
+    }
+
+    /**
+     * Places the string representation of extension value
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        buffer.append(prefix).append("BasicConstraints [\n").append(prefix) //$NON-NLS-1$
+            .append("  CA: ").append(cA) //$NON-NLS-1$
+            .append("\n  ").append(prefix).append("pathLenConstraint: ") //$NON-NLS-1$ //$NON-NLS-2$
+            .append(pathLenConstraint).append('\n').append(prefix)
+            .append("]\n"); //$NON-NLS-1$
+    }
+
+    /**
+     * ASN.1 Encoder/Decoder.
+     */
+    public static ASN1Type ASN1 = new ASN1Sequence(new ASN1Type[] {
+            ASN1Boolean.getInstance(), ASN1Integer.getInstance() }) {
+        {
+            setDefault(Boolean.FALSE, 0);
+            setOptional(1);
+        }
+
+        public Object getDecodedObject(BerInputStream in)
+                throws IOException {
+            return in.content;
+        }
+
+        protected void getValues(Object object, Object[] values) {
+            Object[] vals = (Object[]) object;
+            values[0] = (Boolean) vals[0];
+            values[1] = ((BigInteger) vals[1]).toByteArray();
+        }
+
+    };
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/CRLDistributionPoints.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/CRLDistributionPoints.java
new file mode 100644
index 0000000..eb73e61
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/CRLDistributionPoints.java
@@ -0,0 +1,137 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.harmony.security.asn1.ASN1SequenceOf;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with the CRL Distribution Points which is the part of X.509 Certificate
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *
+ * <pre>
+ *  CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
+ *
+ *  DistributionPoint ::= SEQUENCE {
+ *        distributionPoint       [0]     DistributionPointName OPTIONAL,
+ *        reasons                 [1]     ReasonFlags OPTIONAL,
+ *        cRLIssuer               [2]     GeneralNames OPTIONAL 
+ *  }
+ *
+ *  DistributionPointName ::= CHOICE {
+ *        fullName                [0]     GeneralNames,
+ *        nameRelativeToCRLIssuer [1]     RelativeDistinguishedName 
+ *  }
+ *
+ *  ReasonFlags ::= BIT STRING {
+ *        unused                  (0),
+ *        keyCompromise           (1),
+ *        cACompromise            (2),
+ *        affiliationChanged      (3),
+ *        superseded              (4),
+ *        cessationOfOperation    (5),
+ *        certificateHold         (6),
+ *        privilegeWithdrawn      (7),
+ *        aACompromise            (8) 
+ *  }
+ * </pre>
+ */
+public class CRLDistributionPoints extends ExtensionValue {
+    
+    private List distributionPoints;
+    private byte[] encoding;
+    
+    public CRLDistributionPoints(List distributionPoints) {
+        if ((distributionPoints == null) 
+                || (distributionPoints.size() == 0)) {
+            throw new IllegalArgumentException(Messages.getString("security.17D")); //$NON-NLS-1$
+        }
+        this.distributionPoints = distributionPoints;
+    }
+
+    public CRLDistributionPoints(List distributionPoints, byte[] encoding) {
+        if ((distributionPoints == null) 
+                || (distributionPoints.size() == 0)) {
+            throw new IllegalArgumentException(Messages.getString("security.17D")); //$NON-NLS-1$
+        }
+        this.distributionPoints = distributionPoints;
+        this.encoding = encoding;
+    }
+
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    public static CRLDistributionPoints decode(byte[] encoding) 
+            throws IOException {
+        CRLDistributionPoints cdp = (CRLDistributionPoints) ASN1.decode(encoding);
+        return cdp;
+    }
+
+    /**
+     * Places the string representation of extension value
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        buffer.append(prefix).append("CRL Distribution Points: [\n"); //$NON-NLS-1$
+        int number = 0;
+        for (Iterator it=distributionPoints.iterator();
+                it.hasNext();) {
+            buffer.append(prefix).append("  [").append(++number).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$
+            ((DistributionPoint) it.next()).dumpValue(buffer, prefix + "  "); //$NON-NLS-1$
+        }
+        buffer.append(prefix).append("]\n"); //$NON-NLS-1$
+    }
+    
+    /**
+     * Custom X.509 decoder.
+     */
+    public static final ASN1Type ASN1 = 
+        new ASN1SequenceOf(DistributionPoint.ASN1) {
+
+        public Object getDecodedObject(BerInputStream in) {
+            return new CRLDistributionPoints((List)in.content, 
+                    in.getEncoded());
+        }
+
+        public Collection getValues(Object object) {
+            CRLDistributionPoints dps = (CRLDistributionPoints) object;
+            return dps.distributionPoints;
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/CRLNumber.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/CRLNumber.java
new file mode 100644
index 0000000..85cbea0
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/CRLNumber.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+import org.apache.harmony.security.asn1.ASN1Integer;
+import org.apache.harmony.security.asn1.ASN1Type;
+
+/**
+ * CRL Entry's CRL Number Extension (OID = 2.5.29.20).
+ * <pre>
+ *   id-ce-cRLNumber OBJECT IDENTIFIER ::= { id-ce 20 }
+ *
+ *   CRLNumber ::= INTEGER (0..MAX)
+ * </pre>
+ * (as specified in RFC 3280 http://www.ietf.org/rfc/rfc3280.txt)
+ */
+public class CRLNumber extends ExtensionValue {
+
+    // crl number value
+    private final BigInteger number;
+
+    /**
+     * Constructs the object on the base of the invalidity date value.
+     */
+    public CRLNumber(BigInteger number) {
+        this.number = number;
+    }
+
+    /**
+     * Constructs the object on the base of its encoded form.
+     */
+    public CRLNumber(byte[] encoding) throws IOException {
+        super(encoding);
+        number = new BigInteger((byte[]) ASN1.decode(encoding));
+    }
+
+    /**
+     * Returns the invalidity date.
+     */
+    public BigInteger getNumber() {
+        return number;
+    }
+
+    /**
+     * Returns ASN.1 encoded form of this X.509 CRLNumber value.
+     * @return a byte array containing ASN.1 encoded form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(number.toByteArray());
+        }
+        return encoding;
+    }
+
+    /**
+     * Places the string representation of extension value
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        buffer.append(prefix).append("CRL Number: [ ").append(number).append( //$NON-NLS-1$
+                " ]\n"); //$NON-NLS-1$
+    }
+
+    /**
+     * ASN.1 Encoder/Decoder.
+     */
+    public static ASN1Type ASN1 = ASN1Integer.getInstance();
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/Certificate.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/Certificate.java
new file mode 100644
index 0000000..27e8dfc
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/Certificate.java
@@ -0,0 +1,166 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import org.apache.harmony.security.asn1.ASN1BitString;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.asn1.BitString;
+import org.apache.harmony.security.utils.Array;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with the X.509 certificate. Its ASN notation is as follows
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *
+ * <pre>
+ *  Certificate  ::=  SEQUENCE  {
+ *      tbsCertificate       TBSCertificate,
+ *      signatureAlgorithm   AlgorithmIdentifier,
+ *      signatureValue       BIT STRING  
+ *  }
+ * </pre>
+ */
+public class Certificate {
+
+    // the value of tbsCertificate field of the structure
+    private final TBSCertificate tbsCertificate; 
+    // the value of signatureAlgorithm field of the structure
+    private final AlgorithmIdentifier signatureAlgorithm;
+    // the value of signatureValue field of the structure
+    private final byte[] signatureValue;
+    // the ASN.1 encoded form of Certificate
+    private byte[] encoding;
+
+    /**
+     * TODO
+     * @param   tbsCertificate: TBSCertificate
+     * @param   signatureAlgorithm: AlgorithmIdentifier
+     * @param   signatureValue: byte[]
+     */
+    public Certificate(TBSCertificate tbsCertificate, 
+                       AlgorithmIdentifier signatureAlgorithm,
+                       byte[] signatureValue) {
+        this.tbsCertificate = tbsCertificate;
+        this.signatureAlgorithm = signatureAlgorithm;
+        this.signatureValue = new byte[signatureValue.length];
+        System.arraycopy(signatureValue, 0, this.signatureValue, 0, 
+                                                    signatureValue.length);
+    }
+    
+    // 
+    // TODO
+    // @param   tbsCertificate: TBSCertificate
+    // @param   signatureAlgorithm: AlgorithmIdentifier
+    // @param   signatureValue: byte[]
+    // @param   encoding:   byte[]
+    // 
+    private Certificate(TBSCertificate tbsCertificate, 
+                       AlgorithmIdentifier signatureAlgorithm,
+                       byte[] signatureValue, byte[] encoding) {
+        this(tbsCertificate, signatureAlgorithm, signatureValue);
+        this.encoding = encoding;
+    }
+    
+    /**
+     * Returns the value of tbsCertificate field of the structure.
+     * @return  tbsCertificate
+     */
+    public TBSCertificate getTbsCertificate() {
+        return tbsCertificate;
+    }
+
+    /**
+     * Returns the value of signatureAlgorithm field of the structure.
+     * @return  signatureAlgorithm
+     */
+    public AlgorithmIdentifier getSignatureAlgorithm() {
+        return signatureAlgorithm;
+    }
+
+    /**
+     * Returns the value of signatureValue field of the structure.
+     * @return  signatureValue
+     */
+    public byte[] getSignatureValue() {
+        byte[] result = new byte[signatureValue.length];
+        System.arraycopy(signatureValue, 0, result, 0, signatureValue.length);
+        return result;
+    }
+
+    public String toString() {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("X.509 Certificate:\n[\n"); //$NON-NLS-1$
+        tbsCertificate.dumpValue(buffer);
+        buffer.append("\n  Algorithm: ["); //$NON-NLS-1$
+        signatureAlgorithm.dumpValue(buffer);
+        buffer.append(']');
+        buffer.append("\n  Signature Value:\n"); //$NON-NLS-1$
+        buffer.append(Array.toString(signatureValue, "")); //$NON-NLS-1$
+        buffer.append(']');
+        return buffer.toString();
+    }
+    
+    /**
+     * Returns ASN.1 encoded form of this X.509 TBSCertificate value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = Certificate.ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    /**
+     * X.509 Certificate encoder/decoder.
+     */
+    public static final ASN1Sequence ASN1 = 
+        new ASN1Sequence(new ASN1Type[] 
+                {TBSCertificate.ASN1, AlgorithmIdentifier.ASN1, ASN1BitString.getInstance()}) {
+
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+            return new Certificate(
+                    (TBSCertificate) values[0],
+                    (AlgorithmIdentifier) values[1], 
+                    ((BitString) values[2]).bytes, // FIXME keep as BitString object
+                    in.getEncoded()
+                    );
+        }
+
+        protected void getValues(Object object, Object[] values) {
+
+            Certificate cert = (Certificate) object;
+
+            values[0] = cert.tbsCertificate;
+            values[1] = cert.signatureAlgorithm;
+            values[2] = new BitString(cert.signatureValue, 0);
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/CertificateIssuer.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/CertificateIssuer.java
new file mode 100644
index 0000000..3a31734
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/CertificateIssuer.java
@@ -0,0 +1,102 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+import javax.security.auth.x500.X500Principal;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.x501.Name;
+
+/**
+ * CRL Entry's Certificate Issuer Extension (OID = 2.5.29.29).
+ * It is a CRL entry extension and contains the GeneralNames describing
+ * the issuer of revoked certificate. Its ASN.1 notation is as follows:
+ * <pre>
+ *   id-ce-certificateIssuer   OBJECT IDENTIFIER ::= { id-ce 29 }
+ *
+ *   certificateIssuer ::=     GeneralNames
+ * </pre>
+ * (as specified in RFC 3280)
+ * In java implementation it is presumed that GeneralNames consist of
+ * one element and its type is directoryName.
+ */
+public class CertificateIssuer extends ExtensionValue {
+
+    // certificate issuer value
+    private X500Principal issuer;
+
+    /**
+     * Creates an object on the base of GeneralName structure.
+     */
+    public CertificateIssuer(GeneralName issuer) {
+        super(ASN1.encode(issuer));
+    }
+
+    /**
+     * Creates an object on the base of its encoded form.
+     */
+    public CertificateIssuer(byte[] encoding) {
+        super(encoding);
+    }
+
+    /**
+     * Returns the issuer.
+     */
+    public X500Principal getIssuer() throws IOException {
+        if (issuer == null) {
+            issuer = (X500Principal) ASN1.decode(getEncoded());
+        }
+        return issuer;
+    }
+
+    /**
+     * Places the string representation of extension value
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        buffer.append(prefix).append("Certificate Issuer: "); //$NON-NLS-1$
+        if (issuer == null) {
+            try {
+                issuer = getIssuer();
+            } catch (IOException e) {
+                // incorrect extension value encoding
+                buffer.append("Unparseable (incorrect!) extension value:\n"); //$NON-NLS-1$
+                super.dumpValue(buffer);
+            }
+        }
+        buffer.append(issuer).append('\n');
+    }
+
+    /**
+     * ASN.1 Encoder/Decoder.
+     */
+    public static ASN1Type ASN1 = new ASN1Sequence(new ASN1Type[] {
+        GeneralName.ASN1
+    }) {
+        public Object getDecodedObject(BerInputStream in) {
+            return ((Name) ((GeneralName) ((Object[]) in.content)[0])
+                    .getName()).getX500Principal();
+        }
+
+        protected void getValues(Object object, Object[] values) {
+            values[0] = object;
+        }
+    };
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/CertificateList.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/CertificateList.java
new file mode 100644
index 0000000..5715a72
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/CertificateList.java
@@ -0,0 +1,162 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import org.apache.harmony.security.asn1.ASN1BitString;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.asn1.BitString;
+import org.apache.harmony.security.utils.Array;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with the X.509 CRL. Its ASN notation is as follows
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *
+ * <pre>
+ *  CertificateList  ::=  SEQUENCE  {
+ *       tbsCertList          TBSCertList,
+ *       signatureAlgorithm   AlgorithmIdentifier,
+ *       signatureValue       BIT STRING  
+ *  }
+ * </pre>
+ */
+public class CertificateList {
+    
+    // the value of tbsCertList field of the structure
+    private final TBSCertList tbsCertList; 
+    // the value of signatureAlgorithm field of the structure
+    private final AlgorithmIdentifier signatureAlgorithm;
+    // the value of signatureValue field of the structure
+    private final byte[] signatureValue;
+    // the ASN.1 encoded form of CertList
+    private byte[] encoding;
+
+    /**
+     * TODO
+     * @param   tbsCertList: TBSCertList
+     * @param   signatureAlgorithm: AlgorithmIdentifier
+     * @param   signatureValue: byte[]
+     */
+    public CertificateList(TBSCertList tbsCertList, 
+                       AlgorithmIdentifier signatureAlgorithm,
+                       byte[] signatureValue) {
+        this.tbsCertList = tbsCertList;
+        this.signatureAlgorithm = signatureAlgorithm;
+        this.signatureValue = new byte[signatureValue.length];
+        System.arraycopy(signatureValue, 0, this.signatureValue, 0, 
+                                                    signatureValue.length);
+    }
+    
+    // 
+    // TODO
+    // @param   tbsCertList: TBSCertList
+    // @param   signatureAlgorithm: AlgorithmIdentifier
+    // @param   signatureValue: byte[]
+    // @param   encoding:   byte[]
+    // 
+    private CertificateList(TBSCertList tbsCertList, 
+                       AlgorithmIdentifier signatureAlgorithm,
+                       byte[] signatureValue, byte[] encoding) {
+        this(tbsCertList, signatureAlgorithm, signatureValue);
+        this.encoding = encoding;
+    }
+    
+    /**
+     * Returns the value of tbsCertList field of the structure.
+     * @return  tbsCertList
+     */
+    public TBSCertList getTbsCertList() {
+        return tbsCertList;
+    }
+
+    /**
+     * Returns the value of signatureAlgorithm field of the structure.
+     * @return  signatureAlgorithm
+     */
+    public AlgorithmIdentifier getSignatureAlgorithm() {
+        return signatureAlgorithm;
+    }
+
+    /**
+     * Returns the value of signatureValue field of the structure.
+     * @return  signatureValue
+     */
+    public byte[] getSignatureValue() {
+        byte[] result = new byte[signatureValue.length];
+        System.arraycopy(signatureValue, 0, result, 0, signatureValue.length);
+        return result;
+    }
+
+    public String toString() {
+        StringBuffer res = new StringBuffer();
+        tbsCertList.dumpValue(res);
+        res.append("\nSignature Value:\n"); //$NON-NLS-1$
+        res.append(Array.toString(signatureValue, "")); //$NON-NLS-1$
+        return res.toString();
+    }
+    
+    /**
+     * Returns ASN.1 encoded form of this X.509 TBSCertList value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = CertificateList.ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    /**
+     * X.509 CertList encoder/decoder.
+     */
+    public static final ASN1Sequence ASN1 = 
+        new ASN1Sequence(new ASN1Type[] 
+                {TBSCertList.ASN1, AlgorithmIdentifier.ASN1, 
+                    ASN1BitString.getInstance()}) {
+
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+            return new CertificateList(
+                    (TBSCertList) values[0],
+                    (AlgorithmIdentifier) values[1], 
+                    ((BitString) values[2]).bytes, // FIXME keep as BitString object
+                    in.getEncoded()
+                    );
+        }
+
+        protected void getValues(Object object, Object[] values) {
+
+            CertificateList certlist = (CertificateList) object;
+
+            values[0] = certlist.tbsCertList;
+            values[1] = certlist.signatureAlgorithm;
+            values[2] = new BitString(certlist.signatureValue, 0);
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/CertificatePolicies.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/CertificatePolicies.java
new file mode 100644
index 0000000..0c2267b
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/CertificatePolicies.java
@@ -0,0 +1,151 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.harmony.security.asn1.ASN1SequenceOf;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with Certificate Policies structure which is a part of X.509 certificate
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ * 
+ * <pre>
+ *   certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
+ * </pre>
+ * 
+ */
+
+public class CertificatePolicies extends ExtensionValue {
+
+    // the values of policyInformation field of the structure
+    private List policyInformations;
+    // the ASN.1 encoded form of CertificatePolicies
+    private byte[] encoding;
+    
+    /**
+     * Constructs an object representing the value of CertificatePolicies.
+     */
+    public CertificatePolicies() {}
+    
+    /**
+     * TODO
+     * @param   policyInformations: List
+     */
+    public CertificatePolicies(List policyInformations) {
+        this.policyInformations = policyInformations;
+    }
+
+    public static CertificatePolicies decode(byte[] encoding) 
+            throws IOException {
+        CertificatePolicies cps = ((CertificatePolicies) ASN1.decode(encoding));
+        cps.encoding = encoding;
+        return cps;
+    }
+    
+    // 
+    // TODO
+    // @param   policyInformations: List
+    // @param   encoding:   byte[]
+    // 
+    private CertificatePolicies(List policyInformations, byte[] encoding) {
+        this.policyInformations = policyInformations;
+        this.encoding = encoding;
+    }
+
+    /**
+     * Returns the values of policyInformation field of the structure.
+     * @return  policyInformations
+     */
+    public List getPolicyInformations() {
+        return new ArrayList(policyInformations);
+    }
+
+    /**
+     * TODO
+     * @param   policyInformation:  PolicyInformation
+     * @return
+     */
+    public CertificatePolicies addPolicyInformation(
+            PolicyInformation policyInformation) {
+        encoding = null;
+        if (policyInformations == null) {
+            policyInformations = new ArrayList();
+        }
+        policyInformations.add(policyInformation);
+        return this;
+    }
+
+    /**
+     * Returns ASN.1 encoded form of this X.509 CertificatePolicies value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    /**
+     * Places the string representation of extension value 
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        buffer.append(prefix).append("CertificatePolicies [\n"); //$NON-NLS-1$
+        for (Iterator it=policyInformations.iterator(); it.hasNext();) {
+            buffer.append(prefix);
+            buffer.append("  "); //$NON-NLS-1$
+            ((PolicyInformation) it.next()).dumpValue(buffer);
+            buffer.append('\n');
+        }
+        buffer.append(prefix).append("]\n"); //$NON-NLS-1$
+    }
+
+    /**
+     * ASN.1 DER X.509 CertificatePolicies encoder/decoder class.
+     */
+    public static final ASN1Type ASN1 = 
+        new ASN1SequenceOf(PolicyInformation.ASN1) {
+
+        public Object getDecodedObject(BerInputStream in) {
+            return new CertificatePolicies((List) in.content, in.getEncoded());
+        }
+
+        public Collection getValues(Object object) {
+            CertificatePolicies cps = (CertificatePolicies) object;
+            return cps.policyInformations;
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/DNParser.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/DNParser.java
new file mode 100644
index 0000000..730f7df
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/DNParser.java
@@ -0,0 +1,468 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Esin, Stepan M. Mishura
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.harmony.security.internal.nls.Messages;
+import org.apache.harmony.security.x501.AttributeTypeAndValue;
+import org.apache.harmony.security.x501.AttributeValue;
+
+
+/**
+ * Distinguished Name Parser.
+ * 
+ * Parses a distinguished name(DN) string according
+ * BNF syntax specified in RFC 2253 and RFC 1779
+ * 
+ * RFC 2253: Lightweight Directory Access Protocol (v3):
+ *           UTF-8 String Representation of Distinguished Names
+ *   http://www.ietf.org/rfc/rfc2253.txt
+ * 
+ * RFC 1779: A String Representation of Distinguished Names
+ *   http://www.ietf.org/rfc/rfc1779.txt
+ */
+public class DNParser {
+
+    // length of distinguished name string
+    protected final int length;
+
+    protected int pos, beg, end;
+
+    // tmp vars to store positions of the currently parsed item
+    protected int cur;
+
+    // distinguished name chars
+    protected char[] chars;
+
+    // raw string contains '"' or '\'
+    protected boolean hasQE;
+
+    // DER encoding of currently parsed item
+    protected byte[] encoded;
+
+    /**
+     * Constructs DN parser
+     * 
+     * @param dn - distinguished name string to be parsed
+     */
+    public DNParser(String dn) throws IOException {
+        this.length = dn.length();
+        chars = dn.toCharArray();
+    }
+
+    // gets next attribute type: (ALPHA 1*keychar) / oid
+    protected String nextAT() throws IOException {
+
+        hasQE = false; // reset
+
+        // skip preceding space chars, they can present after
+        // comma or semicolon (compatibility with RFC 1779)
+        for (; pos < length && chars[pos] == ' '; pos++) {
+        }
+        if (pos == length) {
+            return null; // reached the end of DN
+        }
+
+        // mark the beginning of attribute type
+        beg = pos;
+
+        // attribute type chars
+        pos++;
+        for (; pos < length && chars[pos] != '=' && chars[pos] != ' '; pos++) {
+            // we don't follow exact BNF syntax here:
+            // accept any char except space and '='
+        }
+        if (pos >= length) {
+            // unexpected end of DN
+            throw new IOException(
+                    Messages.getString("security.192")); //$NON-NLS-1$
+        }
+
+        // mark the end of attribute type
+        end = pos;
+
+        // skip trailing space chars between attribute type and '='
+        // (compatibility with RFC 1779)
+        if (chars[pos] == ' ') {
+            for (; pos < length && chars[pos] != '=' && chars[pos] == ' '; pos++) {
+            }
+
+            if (chars[pos] != '=' || pos == length) {
+                // unexpected end of DN
+                throw new IOException(
+                        Messages.getString("security.192")); //$NON-NLS-1$
+            }
+        }
+
+        pos++; //skip '=' char
+
+        // skip space chars between '=' and attribute value
+        // (compatibility with RFC 1779)
+        for (; pos < length && chars[pos] == ' '; pos++) {
+        }
+
+        // in case of oid attribute type skip its prefix: "oid." or "OID."
+        // (compatibility with RFC 1779)
+        if ((end - beg > 4) && (chars[beg + 3] == '.')
+                && (chars[beg] == 'O' || chars[beg] == 'o')
+                && (chars[beg + 1] == 'I' || chars[beg + 1] == 'i')
+                && (chars[beg + 2] == 'D' || chars[beg + 2] == 'd')) {
+            beg += 4;
+        }
+
+        return new String(chars, beg, end - beg);
+    }
+
+    // gets quoted attribute value: QUOTATION *( quotechar / pair ) QUOTATION 
+    protected String quotedAV() throws IOException {
+
+        pos++;
+        beg = pos;
+        end = beg;
+        while (true) {
+
+            if (pos == length) {
+                // unexpected end of DN
+                throw new IOException(
+                        Messages.getString("security.192")); //$NON-NLS-1$
+            }
+
+            if (chars[pos] == '"') {
+                // enclosing quotation was found
+                pos++;
+                break;
+            } else if (chars[pos] == '\\') {
+                chars[end] = getEscaped();
+            } else {
+                // shift char: required for string with escaped chars
+                chars[end] = chars[pos];
+            }
+            pos++;
+            end++;
+        }
+
+        // skip trailing space chars before comma or semicolon.
+        // (compatibility with RFC 1779)
+        for (; pos < length && chars[pos] == ' '; pos++) {
+        }
+
+        return new String(chars, beg, end - beg);
+    }
+
+    // gets hex string attribute value: "#" hexstring
+    private String hexAV() throws IOException {
+
+        if (pos + 4 >= length) {
+            // encoded byte array  must be not less then 4 c
+            throw new IOException(
+                    Messages.getString("security.192")); //$NON-NLS-1$
+        }
+
+        beg = pos; // store '#' position
+        pos++;
+        while (true) {
+
+            // check for end of attribute value 
+            // looks for space and component separators
+            if (pos == length || chars[pos] == '+' || chars[pos] == ','
+                    || chars[pos] == ';') {
+                end = pos;
+                break;
+            }
+
+            if (chars[pos] == ' ') {
+                end = pos;
+                pos++;
+                // skip trailing space chars before comma or semicolon.
+                // (compatibility with RFC 1779)
+                for (; pos < length && chars[pos] == ' '; pos++) {
+                }
+                break;
+            } else if (chars[pos] >= 'A' && chars[pos] <= 'F') {
+                chars[pos] += 32; //to low case
+            }
+
+            pos++;
+        }
+
+        // verify length of hex string
+        // encoded byte array  must be not less then 4 and must be even number
+        int hexLen = end - beg; // skip first '#' char
+        if (hexLen < 5 || (hexLen & 1) == 0) {
+            throw new IOException(
+                    Messages.getString("security.192")); //$NON-NLS-1$
+        }
+
+        // get byte encoding from string representation
+        encoded = new byte[hexLen / 2];
+        for (int i = 0, p = beg + 1; i < encoded.length; p += 2, i++) {
+            encoded[i] = (byte) getByte(p);
+        }
+
+        return new String(chars, beg, hexLen);
+    }
+
+    // gets string attribute value: *( stringchar / pair )
+    protected String escapedAV() throws IOException {
+
+        beg = pos;
+        end = pos;
+        while (true) {
+
+            if (pos >= length) {
+                // the end of DN has been found
+                return new String(chars, beg, end - beg);
+            }
+
+            switch (chars[pos]) {
+            case '+':
+            case ',':
+            case ';':
+                // separator char has beed found
+                return new String(chars, beg, end - beg);
+            case '\\':
+                // escaped char
+                chars[end++] = getEscaped();
+                pos++;
+                break;
+            case ' ':
+                // need to figure out whether space defines
+                // the end of attribute value or not                 
+                cur = end;
+
+                pos++;
+                chars[end++] = ' ';
+
+                for (; pos < length && chars[pos] == ' '; pos++) {
+                    chars[end++] = ' ';
+                }
+                if (pos == length || chars[pos] == ',' || chars[pos] == '+'
+                        || chars[pos] == ';') {
+                    // separator char or the end of DN has beed found
+                    return new String(chars, beg, cur - beg);
+                }
+                break;
+            default:
+                chars[end++] = chars[pos];
+                pos++;
+            }
+        }
+    }
+
+    // returns escaped char
+    private char getEscaped() throws IOException {
+
+        pos++;
+        if (pos == length) {
+            throw new IOException(
+                    Messages.getString("security.192")); //$NON-NLS-1$
+        }
+
+        switch (chars[pos]) {
+        case '"':
+        case '\\':
+            hasQE = true;
+        case ',':
+        case '=':
+        case '+':
+        case '<':
+        case '>':
+        case '#':
+        case ';':
+        case ' ':
+            //FIXME: escaping is allowed only for leading or trailing space char 
+            return chars[pos];
+        default:
+            // RFC doesn't explicitly say that escaped hex pair is 
+            // interpreted as UTF-8 char. It only contains an example of such DN.
+            return getUTF8();
+        }
+    }
+
+    // decodes UTF-8 char
+    // see http://www.unicode.org for UTF-8 bit distribution table
+    protected char getUTF8() throws IOException {
+
+        int res = getByte(pos);
+        pos++; //FIXME tmp
+
+        if (res < 128) { // one byte: 0-7F
+            return (char) res;
+        } else if (res >= 192 && res <= 247) {
+
+            int count;
+            if (res <= 223) { // two bytes: C0-DF
+                count = 1;
+                res = res & 0x1F;
+            } else if (res <= 239) { // three bytes: E0-EF
+                count = 2;
+                res = res & 0x0F;
+            } else { // four bytes: F0-F7
+                count = 3;
+                res = res & 0x07;
+            }
+
+            int b;
+            for (int i = 0; i < count; i++) {
+                pos++;
+                if (pos == length || chars[pos] != '\\') {
+                    return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
+                }
+                pos++;
+
+                b = getByte(pos);
+                pos++; //FIXME tmp
+                if ((b & 0xC0) != 0x80) {
+                    return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
+                }
+
+                res = (res << 6) + (b & 0x3F);
+            }
+            return (char) res;
+        } else {
+            return 0x3F; //FIXME failed to decode UTF-8 char - return '?'
+        }
+    }
+
+    // Returns byte representation of a char pair
+    // The char pair is composed of DN char in
+    // specified 'position' and the next char
+    // According to BNF syntax:
+    // hexchar    = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
+    //                    / "a" / "b" / "c" / "d" / "e" / "f"
+    protected int getByte(int position) throws IOException {
+
+        if ((position + 1) >= length) {
+            // to avoid ArrayIndexOutOfBoundsException
+            throw new IOException(
+                    Messages.getString("security.192")); //$NON-NLS-1$
+        }
+
+        int b1, b2;
+
+        b1 = chars[position];
+        if (b1 >= '0' && b1 <= '9') {
+            b1 = b1 - '0';
+        } else if (b1 >= 'a' && b1 <= 'f') {
+            b1 = b1 - 87; // 87 = 'a' - 10
+        } else if (b1 >= 'A' && b1 <= 'F') {
+            b1 = b1 - 55; // 55 = 'A' - 10
+        } else {
+            throw new IOException(
+                    Messages.getString("security.192")); //$NON-NLS-1$
+        }
+
+        b2 = chars[position + 1];
+        if (b2 >= '0' && b2 <= '9') {
+            b2 = b2 - '0';
+        } else if (b2 >= 'a' && b2 <= 'f') {
+            b2 = b2 - 87; // 87 = 'a' - 10
+        } else if (b2 >= 'A' && b2 <= 'F') {
+            b2 = b2 - 55; // 55 = 'A' - 10
+        } else {
+            throw new IOException(
+                    Messages.getString("security.192")); //$NON-NLS-1$
+        }
+
+        return (b1 << 4) + b2;
+    }
+
+    /**
+     * Parses DN
+     *
+     * @return a list of Relative Distinguished Names(RND),
+     *         each RDN is represented as a list of AttributeTypeAndValue objects
+     */
+    public List parse() throws IOException {
+
+        List list = new ArrayList();
+
+        String attValue;
+        String attType = nextAT();
+        if (attType == null) {
+            return list; //empty list of RDNs 
+        }
+
+        List atav = new ArrayList();
+        while (true) {
+
+            if (pos == length) {
+
+                //empty Attribute Value
+                atav.add(new AttributeTypeAndValue(attType, new AttributeValue(
+                        "", false))); //$NON-NLS-1$
+                list.add(0, atav);
+
+                return list;
+            }
+
+            switch (chars[pos]) {
+            case '"':
+                attValue = quotedAV();
+                atav.add(new AttributeTypeAndValue(attType, new AttributeValue(
+                        attValue, hasQE)));
+                break;
+            case '#':
+                attValue = hexAV();
+
+                atav.add(new AttributeTypeAndValue(attType, new AttributeValue(
+                        attValue, encoded)));
+                break;
+            case '+':
+            case ',':
+            case ';': // compatibility with RFC 1779: semicolon can separate RDNs
+                //empty attribute value
+                atav.add(new AttributeTypeAndValue(attType, new AttributeValue(
+                        "", false))); //$NON-NLS-1$
+                break;
+            default:
+                attValue = escapedAV();
+                atav.add(new AttributeTypeAndValue(attType, new AttributeValue(
+                        attValue, hasQE)));
+            }
+
+            if (pos >= length) {
+                list.add(0, atav);
+                return list;
+            }
+
+            if (chars[pos] == ',' || chars[pos] == ';') {
+                list.add(0, atav);
+                atav = new ArrayList();
+            } else if (chars[pos] != '+') {
+                throw new IOException(
+                        Messages.getString("security.192")); //$NON-NLS-1$
+            }
+
+            pos++;
+            attType = nextAT();
+            if (attType == null) {
+                throw new IOException(
+                        Messages.getString("security.192")); //$NON-NLS-1$
+            }
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/DistributionPoint.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/DistributionPoint.java
new file mode 100644
index 0000000..5751ca2
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/DistributionPoint.java
@@ -0,0 +1,145 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+
+import org.apache.harmony.security.asn1.ASN1Explicit;
+import org.apache.harmony.security.asn1.ASN1Implicit;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with the DistributionPoint structure which is the part of X.509 CRL
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *
+ * <pre>
+ *  CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
+ *
+ *  DistributionPoint ::= SEQUENCE {
+ *        distributionPoint       [0]     DistributionPointName OPTIONAL,
+ *        reasons                 [1]     ReasonFlags OPTIONAL,
+ *        cRLIssuer               [2]     GeneralNames OPTIONAL 
+ *  }
+ *
+ *  DistributionPointName ::= CHOICE {
+ *        fullName                [0]     GeneralNames,
+ *        nameRelativeToCRLIssuer [1]     RelativeDistinguishedName 
+ *  }
+ *
+ *  ReasonFlags ::= BIT STRING {
+ *        unused                  (0),
+ *        keyCompromise           (1),
+ *        cACompromise            (2),
+ *        affiliationChanged      (3),
+ *        superseded              (4),
+ *        cessationOfOperation    (5),
+ *        certificateHold         (6),
+ *        privilegeWithdrawn      (7),
+ *        aACompromise            (8) 
+ *  }
+ * </pre>
+ */
+public class DistributionPoint {
+   
+    private final DistributionPointName distributionPoint;
+    private final ReasonFlags reasons;
+    private final GeneralNames cRLIssuer;
+    
+    public DistributionPoint() {
+        distributionPoint = null;
+        reasons = null;
+        cRLIssuer = null;
+    }
+
+    public DistributionPoint(DistributionPointName distributionPoint,
+            ReasonFlags reasons, GeneralNames cRLIssuer) {
+        if ((reasons != null) && (distributionPoint == null) 
+                && (cRLIssuer == null)) {
+            throw new IllegalArgumentException(
+                    Messages.getString("security.17F")); //$NON-NLS-1$
+        }
+        this.distributionPoint = distributionPoint;
+        this.reasons = reasons;
+        this.cRLIssuer = cRLIssuer;
+    }
+
+    /**
+     * Places the string representation of extension value
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        buffer.append(prefix);
+        buffer.append("Distribution Point: [\n"); //$NON-NLS-1$
+        if (distributionPoint != null) {
+            distributionPoint.dumpValue(buffer, prefix + "  "); //$NON-NLS-1$
+        }
+        if (reasons != null) {
+            reasons.dumpValue(buffer, prefix + "  "); //$NON-NLS-1$
+        }
+        if (cRLIssuer != null) {
+            buffer.append(prefix);
+            buffer.append("  CRL Issuer: [\n"); //$NON-NLS-1$
+            cRLIssuer.dumpValue(buffer, prefix + "    "); //$NON-NLS-1$
+            buffer.append(prefix);
+            buffer.append("  ]\n"); //$NON-NLS-1$
+        }
+        buffer.append(prefix);
+        buffer.append("]\n"); //$NON-NLS-1$
+    }
+
+    /**
+     * Custom X.509 decoder.
+     */
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
+                new ASN1Explicit(0, DistributionPointName.ASN1),
+                new ASN1Implicit(1, ReasonFlags.ASN1),
+                new ASN1Implicit(2, GeneralNames.ASN1)
+            }) {
+        {
+            setOptional(0);
+            setOptional(1);
+            setOptional(2);
+        }
+
+        protected Object getDecodedObject(BerInputStream in) throws IOException {
+            Object[] values = (Object[]) in.content;
+            return new DistributionPoint((DistributionPointName) values[0], 
+                    (ReasonFlags) values[1], (GeneralNames) values[2]);
+        }
+
+        protected void getValues(Object object, Object[] values) {
+            DistributionPoint dp = (DistributionPoint) object;
+            values[0] = dp.distributionPoint;
+            values[1] = dp.reasons;
+            values[2] = dp.cRLIssuer;
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/DistributionPointName.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/DistributionPointName.java
new file mode 100644
index 0000000..c7d8ffa
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/DistributionPointName.java
@@ -0,0 +1,136 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.asn1.ASN1Choice;
+import org.apache.harmony.security.asn1.ASN1Implicit;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.x501.Name;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with the DistributionPointName structure which is the part 
+ * of X.509 CRL
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *
+ * <pre>
+ *  CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
+ *
+ *  DistributionPoint ::= SEQUENCE {
+ *        distributionPoint       [0]     DistributionPointName OPTIONAL,
+ *        reasons                 [1]     ReasonFlags OPTIONAL,
+ *        cRLIssuer               [2]     GeneralNames OPTIONAL 
+ *  }
+ *
+ *  DistributionPointName ::= CHOICE {
+ *        fullName                [0]     GeneralNames,
+ *        nameRelativeToCRLIssuer [1]     RelativeDistinguishedName 
+ *  }
+ *
+ *  ReasonFlags ::= BIT STRING {
+ *        unused                  (0),
+ *        keyCompromise           (1),
+ *        cACompromise            (2),
+ *        affiliationChanged      (3),
+ *        superseded              (4),
+ *        cessationOfOperation    (5),
+ *        certificateHold         (6),
+ *        privilegeWithdrawn      (7),
+ *        aACompromise            (8) 
+ *  }
+ * </pre>
+ */
+public class DistributionPointName {
+   
+    private final GeneralNames fullName;
+    private final Name nameRelativeToCRLIssuer;
+
+
+    public DistributionPointName(GeneralNames fullName) {
+        this.fullName = fullName;
+        this.nameRelativeToCRLIssuer = null;
+    }
+    
+    public DistributionPointName(Name nameRelativeToCRLIssuer) {
+        this.fullName = null;
+        this.nameRelativeToCRLIssuer = nameRelativeToCRLIssuer;
+    }
+
+    /**
+     * Places the string representation of extension value
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        buffer.append(prefix);
+        buffer.append("Distribution Point Name: [\n"); //$NON-NLS-1$
+        if (fullName != null) {
+            fullName.dumpValue(buffer, prefix + "  "); //$NON-NLS-1$
+        } else {
+            buffer.append(prefix);
+            buffer.append("  "); //$NON-NLS-1$
+            buffer.append(nameRelativeToCRLIssuer.getName(
+                        X500Principal.RFC2253));
+        } 
+        buffer.append(prefix);
+        buffer.append("]\n"); //$NON-NLS-1$
+    }
+
+    public static final ASN1Choice ASN1 = new ASN1Choice(new ASN1Type[] {
+            new ASN1Implicit(0, GeneralNames.ASN1), 
+            new ASN1Implicit(1, Name.ASN1_RDN) }) {
+
+        public int getIndex(java.lang.Object object) {
+            DistributionPointName dpn = (DistributionPointName) object;
+            return (dpn.fullName == null) ? 1 : 0;
+        }
+
+        protected Object getDecodedObject(BerInputStream in) throws IOException {
+            DistributionPointName result = null;
+            if (in.choiceIndex == 0) {
+                result = new DistributionPointName((GeneralNames) in.content);
+            } else {
+                // note: ASN.1 decoder will report an error if index 
+                // is neither 0 or 1
+                result = new DistributionPointName((Name) in.content);
+            }
+            return result;
+        }
+
+        public Object getObjectToEncode(Object object) {
+            DistributionPointName dpn = (DistributionPointName) object;
+            if (dpn.fullName == null) {
+                return dpn.nameRelativeToCRLIssuer;
+            } else {
+                return dpn.fullName;
+            }
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/EDIPartyName.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/EDIPartyName.java
new file mode 100644
index 0000000..f5976c0
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/EDIPartyName.java
@@ -0,0 +1,136 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import org.apache.harmony.security.asn1.ASN1Explicit;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.x501.DirectoryString;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with the following structure which is a subpart of GeneralName
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *   
+ * <pre>
+ *   EDIPartyName ::= SEQUENCE {
+ *        nameAssigner            [0]     DirectoryString OPTIONAL,
+ *        partyName               [1]     DirectoryString 
+ *   }
+ * 
+ *   DirectoryString ::= CHOICE {
+ *        teletexString             TeletexString   (SIZE (1..MAX)),
+ *        printableString           PrintableString (SIZE (1..MAX)),
+ *        universalString           UniversalString (SIZE (1..MAX)),
+ *        utf8String              UTF8String      (SIZE (1..MAX)),
+ *        bmpString               BMPString       (SIZE (1..MAX)) 
+ *   }
+ * </pre>
+ */
+public class EDIPartyName {
+    // the value of nameAssigner field of the structure
+    private String nameAssigner;
+    // the value of partyName field of the structure
+    private String partyName;
+    // the ASN.1 encoded form of EDIPartyName
+    private byte[] encoding;
+    
+    /**
+     * TODO
+     * @param   nameAssigner:   String
+     * @param   partyName:  String
+     */
+    public EDIPartyName(String nameAssigner, String partyName) {
+        this.nameAssigner = nameAssigner;
+        this.partyName = partyName;
+    }
+    
+    // 
+    // TODO
+    // @param   nameAssigner:   String
+    // @param   partyName:  String
+    // @param   encoding:   byte[]
+    // 
+    private EDIPartyName(String nameAssigner, String partyName, 
+                         byte[] encoding) {
+        this.nameAssigner = nameAssigner;
+        this.partyName = partyName;
+        this.encoding = encoding;
+    }
+    
+    /**
+     * Returns the value of nameAssigner field of the structure.
+     * @return  nameAssigner
+     */
+    public String getNameAssigner() {
+        return nameAssigner;
+    }
+    
+    /**
+     * Returns the value of partyName field of the structure.
+     * @return  partyName
+     */
+    public String getPartyName() {
+        return partyName;
+    }
+    
+    /**
+     * Returns ASN.1 encoded form of this X.509 EDIPartyName value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    /**
+     * ASN.1 DER X.509 EDIPartyName encoder/decoder class.
+     */
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(
+            new ASN1Type[] {
+                new ASN1Explicit(0, DirectoryString.ASN1), 
+                new ASN1Explicit(1, DirectoryString.ASN1)
+            }) {
+        {
+            setOptional(0);
+        }
+
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+            return new EDIPartyName((String) values[0], (String) values[1],
+                    in.getEncoded());
+        }
+
+        protected void getValues(Object object, Object[] values) {
+            EDIPartyName epn = (EDIPartyName) object;
+            values[0] = epn.nameAssigner;
+            values[1] = epn.partyName;
+        }
+    };
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/ExtendedKeyUsage.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/ExtendedKeyUsage.java
new file mode 100644
index 0000000..69e9cee
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/ExtendedKeyUsage.java
@@ -0,0 +1,122 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.ASN1SequenceOf;
+import org.apache.harmony.security.asn1.ASN1Oid;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.asn1.ObjectIdentifier;
+
+/**
+ * Extended Key Usage Extension (OID == 2.5.29.37).
+ *
+ * The ASN.1 definition for Extended Key Usage Extension is:
+ *
+ * <pre>
+ *  id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 }
+ *
+ *  ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
+ *
+ *  KeyPurposeId ::= OBJECT IDENTIFIER
+ * </pre>
+ * (as specified in RFC 3280  http://www.ietf.org/rfc/rfc3280.txt
+ */
+public class ExtendedKeyUsage extends ExtensionValue {
+
+    // the value of extension
+    private List keys;
+
+    /**
+     * Creates an object on the base of list of integer arrays representing
+     * key purpose IDs.
+     */
+    public ExtendedKeyUsage(List keys) {
+        this.keys = keys;
+    }
+
+    /**
+     * Creates the extension object on the base of its encoded form.
+     */
+    public ExtendedKeyUsage(byte[] encoding) {
+        super(encoding);
+    }
+
+    /**
+     * Returns the list of string representation of OIDs corresponding
+     * to key purpose IDs.
+     */
+    public List getExtendedKeyUsage() throws IOException {
+        if (keys == null) {
+            keys = (List) ASN1.decode(getEncoded());
+        }
+        return keys;
+    }
+
+    /**
+     * Returns the encoded form of the object.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(keys);
+        }
+        return encoding;
+    }
+
+    /**
+     * Places the string representation of extension value
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        buffer.append(prefix).append("Extended Key Usage: "); //$NON-NLS-1$
+        if (keys == null) {
+            try {
+                keys = getExtendedKeyUsage();
+            } catch (IOException e) {
+                // incorrect extension value encoding
+                super.dumpValue(buffer);
+                return;
+            }
+        }
+        buffer.append('[');
+        for (Iterator it=keys.iterator(); it.hasNext();) {
+            buffer.append(" \"").append(it.next()).append('"'); //$NON-NLS-1$
+            if (it.hasNext()) {
+                buffer.append(',');
+            }
+        }
+        buffer.append(" ]\n"); //$NON-NLS-1$
+    }
+
+    /**
+     * ASN.1 Encoder/Decoder.
+     */
+    public static ASN1Type ASN1 =
+        new ASN1SequenceOf(new ASN1Oid() {
+
+            public Object getDecodedObject(BerInputStream in)
+                    throws IOException {
+                int[] oid = (int[]) super.getDecodedObject(in);
+                return ObjectIdentifier.toString(oid);
+            }
+
+        });
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/Extension.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/Extension.java
new file mode 100644
index 0000000..833f2fe
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/Extension.java
@@ -0,0 +1,456 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.apache.harmony.security.asn1.ASN1Boolean;
+import org.apache.harmony.security.asn1.ASN1OctetString;
+import org.apache.harmony.security.asn1.ASN1Oid;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.asn1.ObjectIdentifier;
+import org.apache.harmony.security.utils.Array;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with the Extension part of X.509 certificate
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *
+ * <pre>
+ *  Extension  ::=  SEQUENCE  {
+ *       extnID      OBJECT IDENTIFIER,
+ *       critical    BOOLEAN DEFAULT FALSE,
+ *       extnValue   OCTET STRING  
+ *  }
+ * </pre>
+ */
+
+public class Extension {
+    // critical constants
+    public static final boolean CRITICAL = true;
+    public static final boolean NON_CRITICAL = false;
+    
+    // constants: the extension OIDs
+    // certificate extensions:
+    public static final int[] SUBJ_DIRECTORY_ATTRS = {2, 5, 29, 9};
+    public static final int[] SUBJ_KEY_ID = {2, 5, 29, 14};
+    public static final int[] KEY_USAGE = {2, 5, 29, 15};
+    public static final int[] PRIVATE_KEY_USAGE_PERIOD = {2, 5, 29, 16};
+    public static final int[] SUBJECT_ALT_NAME = {2, 5, 29, 17};
+    public static final int[] ISSUER_ALTERNATIVE_NAME = {2, 5, 29, 18};
+    public static final int[] BASIC_CONSTRAINTS = {2, 5, 29, 19};
+    public static final int[] NAME_CONSTRAINTS = {2, 5, 29, 30};
+    public static final int[] CRL_DISTR_POINTS = {2, 5, 29, 31};
+    public static final int[] CERTIFICATE_POLICIES = {2, 5, 29, 32};
+    public static final int[] POLICY_MAPPINGS = {2, 5, 29, 33};
+    public static final int[] AUTH_KEY_ID = {2, 5, 29, 35};
+    public static final int[] POLICY_CONSTRAINTS = {2, 5, 29, 36};
+    public static final int[] EXTENDED_KEY_USAGE = {2, 5, 29, 37};
+    public static final int[] FRESHEST_CRL = {2, 5, 29, 46};
+    public static final int[] INHIBIT_ANY_POLICY = {2, 5, 29, 54};
+    public static final int[] AUTHORITY_INFO_ACCESS =
+                                            {1, 3, 6, 1, 5, 5, 7, 1, 1};
+    public static final int[] SUBJECT_INFO_ACCESS =
+                                            {1, 3, 6, 1, 5, 5, 7, 1, 11};
+    // crl extensions:
+    public static final int[] ISSUING_DISTR_POINT = {2, 5, 29, 28};
+    // crl entry extensions:
+    public static final int[] CRL_NUMBER = {2, 5, 29, 20};
+    public static final int[] CERTIFICATE_ISSUER = {2, 5, 29, 29};
+    public static final int[] INVALIDITY_DATE = {2, 5, 29, 24};
+    public static final int[] REASON_CODE = {2, 5, 29, 21};
+    public static final int[] ISSUING_DISTR_POINTS = {2, 5, 29, 28};
+    
+    // the value of extnID field of the structure
+    private final int[] extnID;
+    private String extnID_str;
+    // the value of critical field of the structure
+    private final boolean critical;
+    // the value of extnValue field of the structure
+    private final byte[] extnValue;
+    // the ASN.1 encoded form of Extension
+    private byte[] encoding;
+    // the raw (not decoded) value of extnValue field of the structure
+    private byte[] rawExtnValue;
+    // the decoded extension value
+    protected ExtensionValue extnValueObject;
+    // tells whether extension value has been decoded or not
+    private boolean valueDecoded = false;
+
+    /**
+     * TODO
+     * @param   extnID: String
+     * @param   critical:   boolean
+     * @param   extnValue:  byte[]
+     */
+    public Extension(String extnID, boolean critical, 
+            ExtensionValue extnValueObject) {
+        this.extnID_str = extnID;
+        this.extnID = ObjectIdentifier.toIntArray(extnID);
+        this.critical = critical;
+        this.extnValueObject = extnValueObject;
+        this.valueDecoded = true;
+        this.extnValue = extnValueObject.getEncoded();
+    }
+        
+    /**
+     * TODO
+     * @param   extnID: String
+     * @param   critical:   boolean
+     * @param   extnValue:  byte[]
+     */
+    public Extension(String extnID, boolean critical, byte[] extnValue) {
+        this.extnID_str = extnID;
+        this.extnID = ObjectIdentifier.toIntArray(extnID);
+        this.critical = critical;
+        this.extnValue = extnValue;
+    }
+        
+    /**
+     * TODO
+     * @param   extnID: int[]
+     * @param   critical:   boolean
+     * @param   extnValue:  byte[]
+     */
+    public Extension(int[] extnID, boolean critical, byte[] extnValue) {
+        this.extnID = extnID;
+        this.critical = critical;
+        this.extnValue = extnValue;
+    }
+        
+    /**
+     * TODO
+     * @param   extnID: String
+     * @param   extnValue:  byte[]
+     */
+    public Extension(String extnID, byte[] extnValue) {
+        this(extnID, NON_CRITICAL, extnValue);
+    }
+
+    /**
+     * TODO
+     * @param   extnID: int[]
+     * @param   extnValue:  byte[]
+     */
+    public Extension(int[] extnID, byte[] extnValue) {
+        this(extnID, NON_CRITICAL, extnValue);
+    }
+
+    // 
+    // TODO
+    // @param   extnID: int[]
+    // @param   critical:   boolean
+    // @param   extnValue:  byte[]
+    // @param   encoding:   byte[]
+    // 
+    private Extension(int[] extnID, boolean critical, byte[] extnValue,
+            byte[] rawExtnValue, byte[] encoding, 
+            ExtensionValue decodedExtValue) {
+        this(extnID, critical, extnValue);
+        this.rawExtnValue = rawExtnValue;
+        this.encoding = encoding;
+        this.extnValueObject = decodedExtValue;
+        this.valueDecoded = (decodedExtValue != null);
+    }
+    
+    /**
+     * Returns the value of extnID field of the structure.
+     * @return  extnID
+     */
+    public String getExtnID() {
+        if (extnID_str == null) {
+            extnID_str = ObjectIdentifier.toString(extnID);
+        }
+        return extnID_str;
+    }
+    
+    /**
+     * Returns the value of critical field of the structure.
+     * @return  critical
+     */
+    public boolean getCritical() {
+        return critical;
+    }
+
+    /**
+     * Returns the value of extnValue field of the structure.
+     * @return  extnValue
+     */
+    public byte[] getExtnValue() {
+        return extnValue;
+    }
+
+    /**
+     * Returns the raw (undecoded octet string) value of extnValue 
+     * field of the structure.
+     * @return  rawExtnValue
+     */
+    public byte[] getRawExtnValue() {
+        if (rawExtnValue == null) {
+            rawExtnValue = ASN1OctetString.getInstance().encode(extnValue);
+        }
+        return rawExtnValue;
+    }
+
+    /**
+     * Returns ASN.1 encoded form of this X.509 Extension value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = Extension.ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    public boolean equals(Object ext) {
+        if (!(ext instanceof Extension)) {
+            return false;
+        }
+        Extension extn = (Extension) ext;
+        return Arrays.equals(extnID, extn.extnID) 
+            && (critical == extn.critical)
+            && Arrays.equals(extnValue, extn.extnValue);
+    }
+
+    public ExtensionValue getDecodedExtensionValue() throws IOException {
+        if (!valueDecoded) {
+            decodeExtensionValue();
+        }
+        return extnValueObject;
+    }
+
+    public KeyUsage getKeyUsageValue() {
+        if (!valueDecoded) {
+            try {
+                decodeExtensionValue();
+            } catch (IOException e) { }
+        }
+        if (extnValueObject instanceof KeyUsage) {
+            return (KeyUsage) extnValueObject;
+        } else {
+            return null;
+        }
+    }
+
+    public BasicConstraints getBasicConstraintsValue() {
+        if (!valueDecoded) {
+            try {
+                decodeExtensionValue();
+            } catch (IOException e) { }
+        }
+        if (extnValueObject instanceof BasicConstraints) {
+            return (BasicConstraints) extnValueObject;
+        } else {
+            return null;
+        }
+    }
+
+    private void decodeExtensionValue() throws IOException {
+        if (valueDecoded) {
+            return;
+        }
+        valueDecoded = true;
+        if (oidEquals(extnID, SUBJ_KEY_ID)) {
+            extnValueObject = SubjectKeyIdentifier.decode(extnValue);
+        } else if (oidEquals(extnID, KEY_USAGE)) {
+            extnValueObject = new KeyUsage(extnValue);
+        } else if (oidEquals(extnID, SUBJECT_ALT_NAME)) {
+            extnValueObject = new AlternativeName(
+                    AlternativeName.SUBJECT, extnValue);
+        } else if (oidEquals(extnID, ISSUER_ALTERNATIVE_NAME)) {
+            extnValueObject = new AlternativeName(
+                    AlternativeName.SUBJECT, extnValue);
+        } else if (oidEquals(extnID, BASIC_CONSTRAINTS)) {
+            extnValueObject = new BasicConstraints(extnValue);
+        } else if (oidEquals(extnID, NAME_CONSTRAINTS)) {
+            extnValueObject = NameConstraints.decode(extnValue);
+        } else if (oidEquals(extnID, CERTIFICATE_POLICIES)) {
+            extnValueObject = CertificatePolicies.decode(extnValue);
+        } else if (oidEquals(extnID, AUTH_KEY_ID)) {
+            extnValueObject = AuthorityKeyIdentifier.decode(extnValue);
+        } else if (oidEquals(extnID, POLICY_CONSTRAINTS)) {
+            extnValueObject = new PolicyConstraints(extnValue);
+        } else if (oidEquals(extnID, EXTENDED_KEY_USAGE)) {
+            extnValueObject = new ExtendedKeyUsage(extnValue);
+        } else if (oidEquals(extnID, INHIBIT_ANY_POLICY)) {
+            extnValueObject = new InhibitAnyPolicy(extnValue);
+        } else if (oidEquals(extnID, CERTIFICATE_ISSUER)) {
+            extnValueObject = new CertificateIssuer(extnValue);
+        } else if (oidEquals(extnID, CRL_DISTR_POINTS)) {
+            extnValueObject = CRLDistributionPoints.decode(extnValue);
+        } else if (oidEquals(extnID, CERTIFICATE_ISSUER)) {
+            extnValueObject = new ReasonCode(extnValue);
+        } else if (oidEquals(extnID, INVALIDITY_DATE)) {
+            extnValueObject = new InvalidityDate(extnValue);
+        } else if (oidEquals(extnID, REASON_CODE)) {
+            extnValueObject = new ReasonCode(extnValue);
+        } else if (oidEquals(extnID, CRL_NUMBER)) {
+            extnValueObject = new CRLNumber(extnValue);
+        } else if (oidEquals(extnID, ISSUING_DISTR_POINTS)) {
+            extnValueObject = IssuingDistributionPoint.decode(extnValue);
+        } else if (oidEquals(extnID, AUTHORITY_INFO_ACCESS)) {
+            extnValueObject = InfoAccessSyntax.decode(extnValue);
+        } else if (oidEquals(extnID, SUBJECT_INFO_ACCESS)) {
+            extnValueObject = InfoAccessSyntax.decode(extnValue);
+        }
+    }
+
+    /**
+     * Places the string representation into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        buffer.append("OID: ").append(getExtnID()) //$NON-NLS-1$
+            .append(", Critical: ").append(critical).append('\n'); //$NON-NLS-1$
+        if (!valueDecoded) {
+            try {
+                decodeExtensionValue();
+            } catch (IOException e) { }
+        }
+        if (extnValueObject != null) {
+            extnValueObject.dumpValue(buffer, prefix);
+            return;
+        }
+        // else: dump unparsed hex representation
+        buffer.append(prefix);
+        if (oidEquals(extnID, SUBJ_DIRECTORY_ATTRS)) {
+            buffer.append("Subject Directory Attributes Extension"); //$NON-NLS-1$
+        } else if (oidEquals(extnID, SUBJ_KEY_ID)) {
+            buffer.append("Subject Key Identifier Extension"); //$NON-NLS-1$
+        } else if (oidEquals(extnID, KEY_USAGE)) {
+            buffer.append("Key Usage Extension"); //$NON-NLS-1$
+        } else if (oidEquals(extnID, PRIVATE_KEY_USAGE_PERIOD)) {
+            buffer.append("Private Key Usage Period Extension"); //$NON-NLS-1$
+        } else if (oidEquals(extnID, SUBJECT_ALT_NAME)) {
+            buffer.append("Subject Alternative Name Extension"); //$NON-NLS-1$
+        } else if (oidEquals(extnID, ISSUER_ALTERNATIVE_NAME)) {
+            buffer.append("Issuer Alternative Name Extension"); //$NON-NLS-1$
+        } else if (oidEquals(extnID, BASIC_CONSTRAINTS)) {
+            buffer.append("Basic Constraints Extension"); //$NON-NLS-1$
+        } else if (oidEquals(extnID, NAME_CONSTRAINTS)) {
+            buffer.append("Name Constraints Extension"); //$NON-NLS-1$
+        } else if (oidEquals(extnID, CRL_DISTR_POINTS)) {
+            buffer.append("CRL Distribution Points Extension"); //$NON-NLS-1$
+        } else if (oidEquals(extnID, CERTIFICATE_POLICIES)) {
+            buffer.append("Certificate Policies Extension"); //$NON-NLS-1$
+        } else if (oidEquals(extnID, POLICY_MAPPINGS)) {
+            buffer.append("Policy Mappings Extension"); //$NON-NLS-1$
+        } else if (oidEquals(extnID, AUTH_KEY_ID)) {
+            buffer.append("Authority Key Identifier Extension"); //$NON-NLS-1$
+        } else if (oidEquals(extnID, POLICY_CONSTRAINTS)) {
+            buffer.append("Policy Constraints Extension"); //$NON-NLS-1$
+        } else if (oidEquals(extnID, EXTENDED_KEY_USAGE)) {
+            buffer.append("Extended Key Usage Extension"); //$NON-NLS-1$
+        } else if (oidEquals(extnID, INHIBIT_ANY_POLICY)) {
+            buffer.append("Inhibit Any-Policy Extension"); //$NON-NLS-1$
+        } else if (oidEquals(extnID, AUTHORITY_INFO_ACCESS)) {
+            buffer.append("Authority Information Access Extension"); //$NON-NLS-1$
+        } else if (oidEquals(extnID, SUBJECT_INFO_ACCESS)) {
+            buffer.append("Subject Information Access Extension"); //$NON-NLS-1$
+        } else if (oidEquals(extnID, INVALIDITY_DATE)) {
+            buffer.append("Invalidity Date Extension"); //$NON-NLS-1$
+        } else if (oidEquals(extnID, CRL_NUMBER)) {
+            buffer.append("CRL Number Extension"); //$NON-NLS-1$
+        } else if (oidEquals(extnID, REASON_CODE)) {
+            buffer.append("Reason Code Extension"); //$NON-NLS-1$
+        } else {
+            buffer.append("Unknown Extension"); //$NON-NLS-1$
+        }
+        buffer.append('\n').append(prefix)
+            .append("Unparsed Extension Value:\n"); //$NON-NLS-1$
+        buffer.append(Array.toString(extnValue, prefix));
+    }
+
+
+    // Compares two OIDs
+    private static boolean oidEquals(int[] oid1, int[] oid2) {
+        int length = oid1.length;
+        if (length != oid2.length) {
+            return false;
+        }
+        while (length > 0) {
+            if (oid1[--length] != oid2[length]) {
+                return false;
+            }
+        }
+        return true;
+    }
+    
+    /**
+     * X.509 Extension encoder/decoder.
+     */
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
+            ASN1Oid.getInstance(), 
+            ASN1Boolean.getInstance(),
+            new ASN1OctetString() {
+                public Object getDecodedObject(BerInputStream in) 
+                                                throws IOException {
+                    // first - decoded octet string,
+                    // second - raw encoding of octet string
+                    return new Object[] 
+                        {super.getDecodedObject(in), in.getEncoded()};
+                }
+            }
+        }) {
+        {
+            setDefault(Boolean.FALSE, 1);
+        }
+
+        protected Object getDecodedObject(BerInputStream in) throws IOException {
+            Object[] values = (Object[]) in.content;
+
+            int[] oid = (int[]) values[0];
+            byte[] extnValue = (byte[]) ((Object[]) values[2])[0];
+            byte[] rawExtnValue = (byte[]) ((Object[]) values[2])[1];
+            
+            ExtensionValue decodedExtValue = null;
+            // decode Key Usage and Basic Constraints extension values
+            if (oidEquals(oid, KEY_USAGE)) {
+                decodedExtValue = new KeyUsage(extnValue);
+            } else if (oidEquals(oid, BASIC_CONSTRAINTS)) {
+                decodedExtValue = new BasicConstraints(extnValue);
+            }
+
+            return 
+                new Extension((int[]) values[0],
+                    ((Boolean) values[1]).booleanValue(),
+                    extnValue, rawExtnValue, in.getEncoded(), decodedExtValue);
+        }
+
+        protected void getValues(Object object, Object[] values) {
+
+            Extension ext = (Extension) object;
+
+            values[0] = ext.extnID;
+            values[1] = (ext.critical) ? Boolean.TRUE : Boolean.FALSE;
+            values[2] = ext.extnValue;
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/ExtensionValue.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/ExtensionValue.java
new file mode 100644
index 0000000..afd9f93
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/ExtensionValue.java
@@ -0,0 +1,75 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.security.x509;
+
+import org.apache.harmony.security.utils.Array;
+
+/**
+ * Base class for extension value structures.
+ */
+public class ExtensionValue {
+
+    /**
+     * Encoded form of the extension.
+     */
+    protected byte[] encoding;
+
+    /**
+     * Default constructor.
+     */
+    public ExtensionValue() { }
+
+    /**
+     * Creates the object on the base of its encoded form.
+     */
+    public ExtensionValue(byte[] encoding) {
+        this.encoding = encoding;
+    }
+
+    /**
+     * Returns encoded form of the object.
+     */
+    public byte[] getEncoded() {
+        return encoding;
+    }
+
+    /**
+     * Places the string representation of extension value
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        buffer.append(prefix).append("Unparseable extension value:\n"); //$NON-NLS-1$
+        if (encoding == null) {
+            encoding = getEncoded();
+        }
+        if (encoding == null) {
+            buffer.append("NULL\n"); //$NON-NLS-1$
+        } else {
+            buffer.append(Array.toString(encoding, prefix));
+        }
+    }
+
+    /**
+     * Places the string representation of extension value
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer) {
+        dumpValue(buffer, ""); //$NON-NLS-1$
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/Extensions.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/Extensions.java
new file mode 100644
index 0000000..e98a116
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/Extensions.java
@@ -0,0 +1,419 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.asn1.ASN1SequenceOf;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with the Extensions part of X.509 certificate
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *
+ * <pre>
+ *  Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
+ * </pre>
+ */
+
+public class Extensions {
+
+    // Supported critical extensions oids:
+    private static List SUPPORTED_CRITICAL = Arrays.asList(
+            new String[] {"2.5.29.15", "2.5.29.19", "2.5.29.32", "2.5.29.17",  //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+                "2.5.29.30", "2.5.29.36", "2.5.29.37", "2.5.29.54"}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+    
+    // the values of extensions of the structure
+    private List<Extension> extensions;
+    private Set critical;
+    private Set noncritical;
+    // the flag showing is there any unsupported critical extension
+    // in the list of extensions or not.
+    private boolean hasUnsupported;
+    // map containing the oid of extensions as a keys and
+    // Extension objects as values
+    private HashMap oidMap;
+    // the ASN.1 encoded form of Extensions
+    private byte[] encoding;
+    
+    /**
+     * Constructs an object representing the value of Extensions.
+     */
+    public Extensions() {}
+    
+    /**
+     * TODO
+     * @param   extensions: List
+     */
+    public Extensions(List extensions) {
+        this.extensions = extensions;
+    }
+    
+    /**
+     * Returns the values of extensions.
+     * @return  extensions
+     */
+    public List getExtensions() {
+        return extensions;
+    }
+    
+    public int size() {
+        return (extensions == null) 
+                        ? 0
+                        : extensions.size();
+    }
+    
+    /**
+     * Returns the list of critical extensions.
+     * @return  extensions
+     */
+    public Set getCriticalExtensions() {
+        if (critical == null) {
+            makeOidsLists();
+        }
+        return critical;
+    }
+
+    /**
+     * Returns the list of critical extensions.
+     * @return  extensions
+     */
+    public Set getNonCriticalExtensions() {
+        if (noncritical == null) {
+            makeOidsLists();
+        }
+        return noncritical;
+    }
+
+    public boolean hasUnsupportedCritical() {
+        if (critical == null) {
+            makeOidsLists();
+        }
+        return hasUnsupported;
+    }
+
+    //
+    // Makes the separated lists with oids of critical 
+    // and non-critical extensions
+    //
+    private void makeOidsLists() {
+        if (extensions == null) {
+            return;
+        }
+        int size = extensions.size();
+        critical = new HashSet(size);
+        noncritical = new HashSet(size);
+        for (int i=0; i<size; i++) {
+            Extension extn = (Extension) extensions.get(i);
+            String oid = extn.getExtnID();
+            if (extn.getCritical()) {
+                if (!SUPPORTED_CRITICAL.contains(oid)) {
+                    hasUnsupported = true;
+                }
+                critical.add(oid);
+            } else {
+                noncritical.add(oid);
+            }
+        }
+    }
+    
+    /**
+     * Returns the values of extensions.
+     * @param oid - the OID of needed extension.
+     * @return  extensions
+     */
+    public Extension getExtensionByOID(String oid) {
+        if (extensions == null) {
+            return null;
+        }
+        if (oidMap == null) {
+            oidMap = new HashMap();
+            Iterator it = extensions.iterator();
+            while (it.hasNext()) {
+                Extension extn = (Extension) it.next();
+                oidMap.put(extn.getExtnID(), extn);
+            }
+        }
+        return (Extension) oidMap.get(oid);
+    }
+
+
+    /**
+     * Returns the value of Key Usage extension (OID == 2.5.29.15).
+     * The ASN.1 definition of Key Usage Extension is:
+     *
+     * <pre> 
+     * id-ce-keyUsage OBJECT IDENTIFIER ::=  { id-ce 15 }
+     *
+     * KeyUsage ::= BIT STRING {
+     *     digitalSignature        (0),
+     *     nonRepudiation          (1),
+     *     keyEncipherment         (2),
+     *     dataEncipherment        (3),
+     *     keyAgreement            (4),
+     *     keyCertSign             (5),
+     *     cRLSign                 (6),
+     *     encipherOnly            (7),
+     *     decipherOnly            (8) 
+     * }
+     * </pre> 
+     * (as specified in RFC 3280)
+     *
+     * @return the value of Key Usage Extension if it is in the list,
+     * and null if there is no such extension or its value can not be decoded
+     * otherwise. Note, that the length of returned array can be greater
+     * than 9.
+     */
+    public boolean[] valueOfKeyUsage() {
+        Extension extn = getExtensionByOID("2.5.29.15"); //$NON-NLS-1$
+        KeyUsage kUsage = null;
+        if ((extn == null) || ((kUsage = extn.getKeyUsageValue()) == null)) {
+            return null;
+        }
+        return kUsage.getKeyUsage();
+    }
+   
+    /**
+     * Returns the value of Extended Key Usage extension (OID == 2.5.29.37).
+     * The ASN.1 definition of Extended Key Usage Extension is:
+     *
+     * <pre> 
+     *  id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 }
+     *  
+     *  ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
+     *  
+     *  KeyPurposeId ::= OBJECT IDENTIFIER
+     * </pre>
+     * (as specified in RFC 3280)
+     *
+     * @return the list with string representations of KeyPurposeId's OIDs
+     * and null
+     * @throws IOException if extension was incorrectly encoded.
+     */
+    public List valueOfExtendedKeyUsage() throws IOException {
+        Extension extn = getExtensionByOID("2.5.29.37"); //$NON-NLS-1$
+        if (extn == null) {
+            return null;
+        }
+        return ((ExtendedKeyUsage) 
+                extn.getDecodedExtensionValue()).getExtendedKeyUsage();
+    }
+    
+    /**
+     * Returns the value of Basic Constraints Extension (OID = 2.5.29.19).
+     * The ASN.1 definition of Basic Constraints Extension is:
+     *
+     * <pre> 
+     *   id-ce-basicConstraints OBJECT IDENTIFIER ::=  { id-ce 19 }
+     *
+     *   BasicConstraints ::= SEQUENCE {
+     *        cA                      BOOLEAN DEFAULT FALSE,
+     *        pathLenConstraint       INTEGER (0..MAX) OPTIONAL 
+     *   }
+     * </pre>
+     * (as specified in RFC 3280)
+     *
+     * @return the value of pathLenConstraint field if extension presents,
+     * and Integer.MAX_VALUE if does not.
+     */
+    public int valueOfBasicConstrains() {
+        Extension extn = getExtensionByOID("2.5.29.19"); //$NON-NLS-1$
+        BasicConstraints bc = null;
+        if ((extn == null) 
+                || ((bc = extn.getBasicConstraintsValue()) == null)) {
+            return Integer.MAX_VALUE;
+        }
+        return bc.getPathLenConstraint();
+    }
+    
+    /**
+     * Returns the value of Subject Alternative Name (OID = 2.5.29.17).
+     * The ASN.1 definition for Subject Alternative Name is:
+     *
+     * <pre> 
+     *  id-ce-subjectAltName OBJECT IDENTIFIER ::=  { id-ce 17 }
+     *  
+     *  SubjectAltName ::= GeneralNames
+     * </pre>
+     * (as specified in RFC 3280)
+     *
+     * @return Returns the collection of pairs: 
+     * (Integer (tag), Object (name value)) if extension presents, and
+     * null if does not.
+     */
+    public List valueOfSubjectAlternativeName() throws IOException {
+        Extension extn = getExtensionByOID("2.5.29.17"); //$NON-NLS-1$
+        if (extn == null) {
+            return null;
+        }
+        return ((GeneralNames) GeneralNames.ASN1.decode(extn.getExtnValue()))
+                .getPairsList();
+    }
+    
+    /**
+     * Returns the value of Issuer Alternative Name Extension (OID = 2.5.29.18).
+     * The ASN.1 definition for Issuer Alternative Name is:
+     *
+     * <pre> 
+     *   id-ce-issuerAltName OBJECT IDENTIFIER ::=  { id-ce 18 }
+     *  
+     *   IssuerAltName ::= GeneralNames
+     * </pre>
+     * (as specified in RFC 3280)
+     *
+     * @return Returns the collection of pairs: 
+     * (Integer (tag), Object (name value)) if extension presents, and
+     * null if does not.
+     */
+    public List valueOfIssuerAlternativeName() throws IOException {
+        Extension extn = getExtensionByOID("2.5.29.18"); //$NON-NLS-1$
+        if (extn == null) {
+            return null;
+        }
+        return ((GeneralNames) 
+                GeneralNames.ASN1.decode(extn.getExtnValue())).getPairsList();
+    }
+   
+    /**
+     * Returns the value of Certificate Issuer Extension (OID = 2.5.29.29). 
+     * It is a CRL entry extension and contains the GeneralNames describing
+     * the issuer of revoked certificate. Its ASN.1 notation is as follows:
+     * <pre>
+     *   id-ce-certificateIssuer   OBJECT IDENTIFIER ::= { id-ce 29 }
+     *
+     *   certificateIssuer ::=     GeneralNames
+     * </pre>
+     * (as specified in RFC 3280)
+     *
+     * @return the value of Certificate Issuer Extension
+     */
+    public X500Principal valueOfCertificateIssuerExtension() 
+                                                        throws IOException {
+        Extension extn = getExtensionByOID("2.5.29.29"); //$NON-NLS-1$
+        if (extn == null) {
+            return null;
+        }
+        return ((CertificateIssuer) 
+                extn.getDecodedExtensionValue()).getIssuer();
+    }
+    
+    /**
+     * TODO
+     * @param   extn:  Extension
+     * @return
+     */
+    public void addExtension(Extension extn) {
+        encoding = null;
+        if (extensions == null) {
+            extensions = new ArrayList();
+        }
+        extensions.add(extn);
+        if (oidMap != null) {
+            oidMap.put(extn.getExtnID(), extn);
+        }
+        if (critical != null) {
+            String oid = extn.getExtnID();
+            if (extn.getCritical()) {
+                if (!SUPPORTED_CRITICAL.contains(oid)) {
+                    hasUnsupported = true;
+                }
+                critical.add(oid);
+            } else {
+                noncritical.add(oid);
+            }
+        }
+    }
+
+    /**
+     * Returns ASN.1 encoded form of this X.509 Extensions value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+    
+    public boolean equals(Object exts) {
+        if (!(exts instanceof Extensions)) {
+            return false;
+        }
+        Extensions extns = (Extensions) exts;
+        return ((extensions == null) || (extensions.size() == 0) 
+                    ? ((extns.extensions == null) 
+                            || (extns.extensions.size() == 0))
+                    : ((extns.extensions == null) 
+                            || (extns.extensions.size() == 0))
+                        ? false
+                        : (extensions.containsAll(extns.extensions)
+                            && (extensions.size() == extns.extensions.size()))
+                );
+    }
+    
+    /**
+     * Places the string representation into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        if (extensions == null) {
+            return;
+        }
+        int num = 1;
+        for (Extension extension: extensions) {
+            buffer.append('\n').append(prefix)
+                .append('[').append(num++).append("]: "); //$NON-NLS-1$
+            extension.dumpValue(buffer, prefix);
+        }
+    }
+
+    /**
+     * Custom X.509 Extensions decoder.
+     */
+    public static final ASN1Type ASN1 = new ASN1SequenceOf(Extension.ASN1) {
+
+        public Object getDecodedObject(BerInputStream in) {
+            return new Extensions((List)in.content);
+        }
+
+        public Collection getValues(Object object) {
+            Extensions exts = (Extensions) object;
+            return (exts.extensions == null) ? new ArrayList() : exts.extensions;
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/GeneralName.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/GeneralName.java
new file mode 100644
index 0000000..db4daaa
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/GeneralName.java
@@ -0,0 +1,945 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.asn1.ASN1Choice;
+import org.apache.harmony.security.asn1.ASN1Implicit;
+import org.apache.harmony.security.asn1.ASN1OctetString;
+import org.apache.harmony.security.asn1.ASN1Oid;
+import org.apache.harmony.security.asn1.ASN1StringType;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.asn1.ObjectIdentifier;
+import org.apache.harmony.security.internal.nls.Messages;
+import org.apache.harmony.security.x501.Name;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with the GeneralName structure which is a part of X.509 certificate
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ * 
+ * <pre>
+ * 
+ *   GeneralName::= CHOICE {
+ *        otherName                       [0]     OtherName,
+ *        rfc822Name                      [1]     IA5String,
+ *        dNSName                         [2]     IA5String,
+ *        x400Address                     [3]     ORAddress,
+ *        directoryName                   [4]     Name,
+ *        ediPartyName                    [5]     EDIPartyName,
+ *        uniformResourceIdentifier       [6]     IA5String,
+ *        iPAddress                       [7]     OCTET STRING,
+ *        registeredID                    [8]     OBJECT IDENTIFIER
+ *   }
+ * 
+ *   OtherName::= SEQUENCE {
+ *        type-id    OBJECT IDENTIFIER,
+ *        value      [0] EXPLICIT ANY DEFINED BY type-id 
+ *   }
+ * 
+ *   EDIPartyName::= SEQUENCE {
+ *        nameAssigner            [0]     DirectoryString OPTIONAL,
+ *        partyName               [1]     DirectoryString 
+ *   }
+ * 
+ *   DirectoryString::= CHOICE {
+ *        teletexString             TeletexString   (SIZE (1..MAX)),
+ *        printableString           PrintableString (SIZE (1..MAX)),
+ *        universalString           UniversalString (SIZE (1..MAX)),
+ *        utf8String              UTF8String      (SIZE (1..MAX)),
+ *        bmpString               BMPString       (SIZE (1..MAX)) 
+ *   }
+ *  
+ * </pre>
+ * 
+ * @see org.apache.harmony.security.x509.NameConstraints
+ * @see org.apache.harmony.security.x509.GeneralSubtree
+ */
+public class GeneralName {
+    
+    /**
+     * The values of the tags of fields
+     */
+    public static final int OTHER_NAME = 0;
+    public static final int RFC822_NAME = 1;
+    public static final int DNS_NAME = 2;
+    public static final int X400_ADDR = 3;
+    public static final int DIR_NAME = 4;
+    public static final int EDIP_NAME = 5;
+    public static final int UR_ID = 6;
+    public static final int IP_ADDR = 7;
+    public static final int REG_ID = 8;
+    
+    // ASN1 encoders/decoders for name choices
+    private static ASN1Type[] nameASN1 = new ASN1Type[9];
+    
+    static {
+        nameASN1[OTHER_NAME] = OtherName.ASN1;
+        nameASN1[RFC822_NAME] = ASN1StringType.IA5STRING;
+        nameASN1[DNS_NAME] = ASN1StringType.IA5STRING;
+        nameASN1[UR_ID] = ASN1StringType.IA5STRING;
+        nameASN1[X400_ADDR] = ORAddress.ASN1;
+        nameASN1[DIR_NAME] = Name.ASN1;
+        nameASN1[EDIP_NAME] = EDIPartyName.ASN1;
+        nameASN1[IP_ADDR] = ASN1OctetString.getInstance();
+        nameASN1[REG_ID] = ASN1Oid.getInstance();
+    }
+    
+    // the tag of the name type
+    private int tag;
+    // the name value (can be String or byte array)
+    private Object name;
+    // the ASN.1 encoded form of GeneralName
+    private byte[] encoding;
+    // the ASN.1 encoded form of GeneralName's field 
+    private byte[] name_encoding;
+
+    /**
+     * Makes the GeneralName object from the tag type and corresponding
+     * well established string representation of the name value.
+     * The String representation of [7] iPAddress is such as:
+     *  For IP v4, as specified in RFC 791, the address must
+     *  contain exactly 4 byte component.  For IP v6, as specified in
+     *  RFC 1883, the address must contain exactly 16 byte component.
+     *  If GeneralName structure is used as a part of Name Constraints
+     *  extension, to represent an address range the number of address
+     *  component is doubled (to 8 and 32 bytes respectively).
+     * Note that the names:
+     * [0] otherName, [3] x400Address, [5] ediPartyName
+     *   have no the string representation, so exception will be thrown.
+     * To make the GeneralName object with such names use another constructor. 
+     * @param tag is an integer which value corresponds to the name type. 
+     * @param name is a name value corresponding to the tag.
+     * <pre>
+     */
+    public GeneralName(int tag, String name) throws IOException {
+        if (name == null) {
+            throw new IOException(Messages.getString("security.28")); //$NON-NLS-1$
+        }
+        this.tag = tag;
+        switch (tag) {
+            case OTHER_NAME :
+            case X400_ADDR :
+            case EDIP_NAME :
+                throw new IOException( Messages.getString("security.180", tag )); //$NON-NLS-1$ //$NON-NLS-2$
+            case DNS_NAME :
+                // according to RFC 3280 p.34 the DNS name should be 
+                // checked against the
+                // RFC 1034 p.10 (3.5. Preferred name syntax):
+                checkDNS(name);
+                this.name = name;
+                break;
+            case UR_ID :
+                // check the uniformResourceIdentifier for correctness
+                // according to RFC 3280 p.34
+                checkURI(name);
+                this.name = name;
+                break;
+            case RFC822_NAME :
+                this.name = name;
+                break;
+            case REG_ID:
+                this.name = oidStrToInts(name);
+                break;
+            case DIR_NAME :
+                this.name = new Name(name);
+                break;
+            case IP_ADDR :
+                this.name = ipStrToBytes(name);
+                break;
+            default:
+                throw new IOException(Messages.getString("security.181", tag)); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+    }
+
+    /**
+     * TODO
+     * @param   name:   OtherName
+     */
+    public GeneralName(OtherName name) {
+        this.tag = OTHER_NAME;
+        this.name = name;
+    }
+
+    /**
+     * TODO
+     * @param   name:   ORAddress
+     */
+    public GeneralName(ORAddress name) {
+        this.tag = X400_ADDR;
+        this.name = name;
+    }
+
+    /**
+     * TODO
+     * @param   name:   Name
+     */
+    public GeneralName(Name name) {
+        this.tag = DIR_NAME;
+        this.name = name;
+    }
+
+    /**
+     * TODO
+     * @param   name:   EDIPartyName
+     */
+    public GeneralName(EDIPartyName name) {
+        this.tag = EDIP_NAME;
+        this.name = name;
+    }
+    /**
+     * Constructor for type [7] iPAddress. 
+     * name is an array of bytes such as:
+     *  For IP v4, as specified in RFC 791, the address must
+     *  contain exactly 4 byte component.  For IP v6, as specified in
+     *  RFC 1883, the address must contain exactly 16 byte component.
+     *  If GeneralName structure is used as a part of Name Constraints
+     *  extension, to represent an address range the number of address
+     *  component is doubled (to 8 and 32 bytes respectively).
+     */
+    public GeneralName(byte[] name) throws IllegalArgumentException {
+        int length = name.length;
+        if (length != 4 && length != 8 && length != 16 && length != 32) {
+            throw new IllegalArgumentException(
+                    Messages.getString("security.182")); //$NON-NLS-1$
+        }
+        this.tag = IP_ADDR;
+        this.name = new byte[name.length];
+        System.arraycopy(name, 0, this.name, 0, name.length);
+    }
+
+    /**
+     * Constructs an object representing the value of GeneralName.
+     * @param tag is an integer which value corresponds
+     * to the name type (0-8), 
+     * @param name is a DER encoded for of the name value
+     */
+    public GeneralName(int tag, byte[] name) 
+                                    throws IOException {
+        if (name == null) {
+            throw new NullPointerException(Messages.getString("security.28")); //$NON-NLS-1$
+        }
+        if ((tag < 0) || (tag > 8)) {
+            throw new IOException(Messages.getString("security.183", tag)); //$NON-NLS-1$
+        }
+        this.tag = tag;
+        this.name_encoding = new byte[name.length];
+        System.arraycopy(name, 0, this.name_encoding, 0, name.length);
+        this.name = nameASN1[tag].decode(this.name_encoding);
+    }
+   
+    /**
+     * Returns the tag of the name in the structure
+     * @return the tag of the name
+     */
+    public int getTag() {
+        return tag;
+    }
+
+    /**
+     * @return the value of the name. 
+     * The class of name object depends on the tag as follows:
+     * [0] otherName - OtherName object,
+     * [1] rfc822Name - String object,
+     * [2] dNSName - String object,
+     * [3] x400Address - ORAddress object,
+     * [4] directoryName - instance of Name object,
+     * [5] ediPartyName - EDIPartyName object,
+     * [6] uniformResourceIdentifier - String object,
+     * [7] iPAddress - array of bytes such as:
+     *  For IP v4, as specified in RFC 791, the address must
+     *  contain exactly 4 byte component.  For IP v6, as specified in
+     *  RFC 1883, the address must contain exactly 16 byte component.
+     *  If GeneralName structure is used as a part of Name Constraints
+     *  extension, to represent an address range the number of address
+     *  component is doubled (to 8 and 32 bytes respectively).
+     * [8] registeredID - String.
+     */
+    public Object getName() {
+        return name;
+    }
+    
+    /**
+     * TODO
+     * @param   _gname: Object
+     * @return
+     */
+    public boolean equals(Object _gname) {
+        if (!(_gname instanceof GeneralName)) {
+            return false;
+        }
+        GeneralName gname = (GeneralName) _gname;
+        if (this.tag != gname.tag) {
+            return false;
+        }
+        switch(tag) {
+            case RFC822_NAME:
+            case DNS_NAME:
+            case UR_ID:
+                return ((String) name).equalsIgnoreCase(
+                        (String) gname.getName());
+            case REG_ID:
+                return Arrays.equals((int[]) name, (int[]) gname.name);
+            case IP_ADDR: 
+                // iPAddress [7], check by using ranges.
+                return Arrays.equals((byte[]) name, (byte[]) gname.name);
+            case DIR_NAME: 
+            case X400_ADDR:
+            case OTHER_NAME:
+            case EDIP_NAME:
+                return Arrays.equals(getEncoded(), gname.getEncoded());
+            default:
+                // should never happen
+        }
+        //System.out.println(false);
+        return false;
+    }
+    
+    /**
+     * Checks if the other general name is acceptable by this object.
+     * The name is acceptable if it has the same type name and its
+     * name value is equal to name value of this object. Also the name
+     * is acceptable if this general name object is a part of name 
+     * constraints and the specified name is satisfied the restriction
+     * provided by this object (for more detail see section 4.2.1.11
+     * of rfc 3280).
+     * Note that for X400Address [3] check procedure is unclear so method
+     * just checks the equality of encoded forms.
+     * For otherName [0], ediPartyName [5], and registeredID [8] 
+     * the check procedure if not defined by rfc 3280 and for names of 
+     * these types this method also checks only for equality of encoded forms.
+     */
+    public boolean isAcceptable(GeneralName gname) {
+        if (this.tag != gname.getTag()) {
+            return false;
+        }
+        switch (this.tag) {
+            case RFC822_NAME:
+                // Mail address [1]: 
+                // a@b.c - particular address is acceptable by the same address,
+                // or by b.c - host name.
+                return ((String) gname.getName()).toLowerCase()
+                    .endsWith(((String) name).toLowerCase());
+            case DNS_NAME:
+                // DNS name [2] that can be constructed by simply adding 
+                // to the left hand side of the name satisfies the name 
+                // constraint: aaa.aa.aa satisfies to aaa.aa.aa, aa.aa, ..
+                String dns = (String) name;
+                String _dns = (String) gname.getName();
+                if (dns.equalsIgnoreCase(_dns)) {
+                    return true;
+                } else {
+                    return _dns.toLowerCase().endsWith("." + dns.toLowerCase()); //$NON-NLS-1$
+                }
+            case UR_ID:
+                // For URIs the constraint ".xyz.com" is satisfied by both 
+                // abc.xyz.com and abc.def.xyz.com.  However, the constraint 
+                // ".xyz.com" is not satisfied by "xyz.com".  
+                // When the constraint does not begin with a period, it
+                // specifies a host.
+                // Extract the host from URI:
+                String uri = (String) name;
+                int begin = uri.indexOf("://")+3; //$NON-NLS-1$
+                int end = uri.indexOf('/', begin);
+                String host = (end == -1) 
+                                ? uri.substring(begin)
+                                : uri.substring(begin, end);
+                uri = (String) gname.getName();
+                begin = uri.indexOf("://")+3; //$NON-NLS-1$
+                end = uri.indexOf('/', begin);
+                String _host = (end == -1) 
+                                ? uri.substring(begin)
+                                : uri.substring(begin, end);
+                if (host.startsWith(".")) { //$NON-NLS-1$
+                    return _host.toLowerCase().endsWith(host.toLowerCase());
+                } else {
+                    return host.equalsIgnoreCase(_host);
+                }
+            case IP_ADDR: 
+                // iPAddress [7], check by using ranges.
+                byte[] address = (byte[]) name;
+                byte[] _address = (byte[]) gname.getName();
+                int length = address.length;
+                int _length = _address.length;
+                if (length == _length) {
+                    return Arrays.equals(address, _address);
+                } else if (length == 2*_length) {
+                    for (int i=0; i<_address.length; i++) {
+                        if ((_address[i] < address[i]) 
+                                || (_address[i] > address[i+_length])) {
+                            return false;
+                        }
+                    }
+                    return true;
+                } else {
+                    return false;
+                }
+            case DIR_NAME: 
+                // FIXME: false:
+                // directoryName according to 4.1.2.4
+                // comparing the encoded forms of the names
+                //TODO:
+                //Legacy implementations exist where an RFC 822 name 
+                //is embedded in the subject distinguished name in an 
+                //attribute of type EmailAddress
+            case X400_ADDR:
+            case OTHER_NAME:
+            case EDIP_NAME:
+            case REG_ID:
+                return Arrays.equals(getEncoded(), gname.getEncoded());
+            default:
+                // should never happen
+        }
+        return true;
+    }
+    
+    /**
+     * Gets a list representation of this GeneralName object.
+     * The first entry of the list is an Integer object representing
+     * the type of mane (0-8), and the second entry is a value of the name:
+     * string or ASN.1 DER encoded form depending on the type as follows:
+     * rfc822Name, dNSName, uniformResourceIdentifier names are returned 
+     * as Strings, using the string formats for those types (rfc 3280)
+     * IP v4 address names are returned using dotted quad notation. 
+     * IP v6 address names are returned in the form "p1:p2:...:p8", 
+     * where p1-p8 are hexadecimal values representing the eight 16-bit 
+     * pieces of the address. registeredID name are returned as Strings 
+     * represented as a series of nonnegative integers separated by periods. 
+     * And directory names (distinguished names) are returned in 
+     * RFC 2253 string format. 
+     * otherName, X400Address, ediPartyName returned as byte arrays 
+     * containing the ASN.1 DER encoded form of the name. 
+     */
+    public List getAsList() {
+        ArrayList result = new ArrayList();
+        result.add(new Integer(tag));
+        switch (tag) {
+            case OTHER_NAME:
+                result.add(((OtherName) name).getEncoded());
+                break;
+            case RFC822_NAME:
+            case DNS_NAME:
+            case UR_ID:
+                result.add(name); // String
+                break;
+            case REG_ID:
+                result.add(ObjectIdentifier.toString((int[]) name));
+                break;
+            case X400_ADDR:
+                result.add(((ORAddress) name).getEncoded());
+                break;
+            case DIR_NAME: // directoryName is returned as a String
+                result.add(((Name) name).getName(X500Principal.RFC2253));
+                break;
+            case EDIP_NAME:
+                result.add(((EDIPartyName) name).getEncoded());
+                break;
+            case IP_ADDR: //iPAddress is returned as a String, not as a byte array
+                result.add(ipBytesToStr((byte[]) name));
+                break;
+            default:
+                // should never happen
+        }
+        return Collections.unmodifiableList(result);
+    }
+
+    // 
+    // TODO
+    // @param   data:   byte[]
+    // @return
+    // 
+    private String getBytesAsString(byte[] data) {
+        String result = ""; //$NON-NLS-1$
+        for (int i=0; i<data.length; i++) {
+            String tail = Integer.toHexString(0x00ff & data[i]);
+            if (tail.length() == 1) {
+                tail = "0" + tail;  //$NON-NLS-1$
+            }
+            result += tail + " "; //$NON-NLS-1$
+        }
+        return result;
+    }
+
+    /**
+     * TODO
+     * @return
+     */
+    public String toString() {
+        String result = ""; //$NON-NLS-1$
+        switch (tag) {
+            case OTHER_NAME:
+                result = "otherName[0]: "  //$NON-NLS-1$
+                         + getBytesAsString(getEncoded());
+                break;
+            case RFC822_NAME:
+                result = "rfc822Name[1]: " + name; //$NON-NLS-1$
+                break;
+            case DNS_NAME:
+                result = "dNSName[2]: " + name; //$NON-NLS-1$
+                break;
+            case UR_ID:
+                result = "uniformResourceIdentifier[6]: " + name; //$NON-NLS-1$
+                break;
+            case REG_ID:
+                result = "registeredID[8]: " + ObjectIdentifier.toString((int[]) name); //$NON-NLS-1$
+                break;
+            case X400_ADDR:
+                result = "x400Address[3]: "  //$NON-NLS-1$
+                         + getBytesAsString(getEncoded());
+                break;
+            case DIR_NAME: 
+                result = "directoryName[4]: "  //$NON-NLS-1$
+                         + ((Name) name).getName(X500Principal.RFC2253);
+                break;
+            case EDIP_NAME:
+                result = "ediPartyName[5]: "  //$NON-NLS-1$
+                         + getBytesAsString(getEncoded());
+                break;
+            case IP_ADDR: 
+                result = "iPAddress[7]: " + ipBytesToStr((byte[]) name); //$NON-NLS-1$
+                break;
+            default:
+                // should never happen
+        }
+        return result;
+    }
+    
+    /**
+     * Returns ASN.1 encoded form of this X.509 GeneralName value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    /**
+     * @return the encoded value of the name without the tag associated 
+     *         with the name in the GeneralName structure
+     * @throws  IOException 
+     */
+    public byte[] getEncodedName() {
+        if (name_encoding == null) {
+            name_encoding = nameASN1[tag].encode(name);
+        }
+        return name_encoding;
+    }
+
+    /**
+     * Checks the correctness of the string representation of DNS name.
+     * The correctness is checked as specified in RFC 1034 p. 10.
+     */
+    public static void checkDNS(String dns) throws IOException {
+        byte[] bytes = dns.toLowerCase().getBytes();
+        // indicates if it is a first letter of the label
+        boolean first_letter = true;
+        for (int i=0; i<bytes.length; i++) {
+            byte ch = bytes[i];
+            if (first_letter) {
+                if (ch > 'z' || ch < 'a') {
+                    throw new IOException(Messages.getString("security.184", //$NON-NLS-1$
+                            (char)ch, dns));
+                }
+                first_letter = false;
+                continue;
+            }
+            if (!((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')
+                    || (ch == '-') || (ch == '.'))) {
+                throw new IOException(Messages.getString("security.185", dns)); //$NON-NLS-1$
+            }
+            if (ch == '.') {
+                // check the end of the previous label, it should not
+                // be '-' sign
+                if (bytes[i-i] == '-') {
+                    throw new IOException(
+                            Messages.getString("security.186", dns)); //$NON-NLS-1$
+                }
+                first_letter = true;
+            }
+        }
+    }
+
+    /**
+     * Checks the correctness of the string representation of URI name.
+     * The correctness is checked as pointed out in RFC 3280 p. 34.
+     */
+    public static void checkURI(String uri) throws IOException {
+        try {
+            URI ur = new URI(uri);
+            if ((ur.getScheme() == null) 
+                    || (ur.getRawSchemeSpecificPart().length() == 0)) {
+                throw new IOException(Messages.getString("security.187", uri)); //$NON-NLS-1$
+            }
+            if (!ur.isAbsolute()) {
+                throw new IOException(Messages.getString("security.188", uri)); //$NON-NLS-1$
+            }
+        } catch (URISyntaxException e) {
+            throw (IOException) new IOException(
+                    Messages.getString("security.189", uri)).initCause(e);//$NON-NLS-1$
+                    
+        }
+    }
+
+    /**
+     * Converts OID into array of bytes.
+     */
+    public static int[] oidStrToInts(String oid) throws IOException {
+        byte[] bytes = oid.getBytes();
+        if (bytes[bytes.length-1] == '.') {
+            throw new IOException(Messages.getString("security.56", oid)); //$NON-NLS-1$
+        }
+        int[] result = new int[bytes.length/2+1]; // best case: a.b.c.d.e
+        int number = 0; // the number of OID's components
+        for (int i=0; i<bytes.length; i++) {
+            int value = 0;
+            int pos = i;
+            while ((i < bytes.length) && (bytes[i] >= '0')
+                        && (bytes[i] <= '9')) {
+                value = 10 * value + (bytes[i++] - 48);
+            }
+            if (i == pos) {
+                // the number was not read
+                throw new IOException(Messages.getString("security.56", oid)); //$NON-NLS-1$
+            }
+            result[number++] = value;
+            if (i >= bytes.length) {
+                break;
+            }
+            if (bytes[i] != '.') {
+                throw new IOException(Messages.getString("security.56", oid)); //$NON-NLS-1$
+            }
+        }
+        if (number < 2) {
+            throw new IOException(Messages.getString("security.18A", oid));//$NON-NLS-1$
+        }
+        int[] res = new int[number];
+        for (int i=0; i<number; i++) {
+            res[i] = result[i];
+        }
+        return res;
+    }
+
+    /**
+     * Helper method. Converts the String representation of IP address
+     * to the array of bytes. IP addresses are expected in two versions:<br>
+     * IPv4 - in dot-decimal notation<br>
+     * IPv6 - in colon hexadecimal notation<br>
+     * Also method works with the ranges of the addresses represented
+     * as 2 addresses separated by '/' character.
+     * @param   address :   String representation of IP address
+     * @return  byte representation of IP address
+     */
+    public static byte[] ipStrToBytes(String ip) throws IOException {
+        boolean isIPv4 = (ip.indexOf('.') > 0);
+        // number of components (should be 4 or 8)
+        int num_components = (isIPv4) ? 4 : 16;
+        if (ip.indexOf('/') > 0) {
+            num_components *= 2; // this is a range of addresses
+        }
+        // the resulting array
+        byte[] result = new byte[num_components];
+        byte[] ip_bytes = ip.getBytes();
+        // number of address component to be read
+        int component = 0;
+        // if it is reading the second bound of a range
+        boolean reading_second_bound = false;
+        if (isIPv4) {
+            // IPv4 address is expected in the form of dot-decimal notation:
+            //      1.100.2.200
+            // or in the range form:
+            //      1.100.2.200/1.100.3.300
+            int i = 0;
+            while (i < ip_bytes.length) {
+                int digits = 0;
+                // the value of the address component
+                int value = 0;
+                while ((i < ip_bytes.length) && (ip_bytes[i] >= '0')
+                        && (ip_bytes[i] <= '9')) {
+                    digits++;
+                    if (digits > 3) {
+                        throw new IOException(Messages.getString("security.18B", ip)); //$NON-NLS-1$
+                    }
+                    value = 10 * value + (ip_bytes[i] - 48);
+                    i++;
+                }
+                if (digits == 0) {
+                    // ip_bytes[i] is not a number
+                    throw new IOException(Messages.getString("security.18C", ip));//$NON-NLS-1$
+                }
+                result[component] = (byte) value;
+                component++;
+                if (i >= ip_bytes.length) {
+                    // no more bytes
+                    break;
+                }
+                // check the reached delimiter
+                if ((ip_bytes[i] != '.' && ip_bytes[i] != '/')) {
+                    throw new IOException(Messages.getString("security.18C", ip)); //$NON-NLS-1$
+                }
+                // check the correctness of the range
+                if (ip_bytes[i] == '/') {
+                    if (reading_second_bound) {
+                        // more than 2 bounds in the range
+                        throw new IOException(Messages.getString("security.18C", ip)); //$NON-NLS-1$
+                    }
+                    if (component != 4) {
+                        throw new IOException(Messages.getString("security.18D", ip)); //$NON-NLS-1$
+                    }
+                    reading_second_bound = true;
+                }
+                // check the number of the components
+                if (component > ((reading_second_bound) ? 7 : 3)) {
+                    throw new IOException(Messages.getString("security.18D", ip)); //$NON-NLS-1$
+                }
+                i++;
+            }
+            // check the number of read components
+            if (component != num_components) {
+                throw new IOException(Messages.getString("security.18D", ip)); //$NON-NLS-1$
+            }
+        } else {
+            // IPv6 address is expected in the form of
+            // colon hexadecimal notation:
+            // 010a:020b:3337:1000:FFFA:ABCD:9999:0000
+            // or in a range form:
+            // 010a:020b:3337:1000:FFFA:ABCD:9999:0000/010a:020b:3337:1000:FFFA:ABCD:9999:1111
+            if (ip_bytes.length != 39 && ip_bytes.length != 79) {
+                // incorrect length of the string representation
+                throw new IOException(Messages.getString("security.18E", ip)); //$NON-NLS-1$
+            }
+            int value = 0;
+            // indicates the reading of the second half of byte
+            boolean second_hex = false;
+            // if the delimiter (':' or '/') is expected
+            boolean expect_delimiter = false;
+            for (int i=0; i<ip_bytes.length; i++) {
+                byte bytik = ip_bytes[i];
+                if ((bytik >= '0') && (bytik <= '9')) {
+                    value = (bytik - 48); // '0':0, '1':1, ... , '9':9
+                } else if ((bytik >= 'A') && (bytik <= 'F')) {
+                    value = (bytik - 55); // 'A':10, 'B':11, ... , 'F':15
+                } else if ((bytik >= 'a') && (bytik <= 'f')) {
+                    value = (bytik - 87); // 'a':10, 'b':11, ... , 'f':15
+                } else if (second_hex) {
+                    // second hex value of a byte is expected but was not read
+                    // (it is the situation like: ...ABCD:A:ABCD...)
+                    throw new IOException(Messages.getString("security.18E", ip)); //$NON-NLS-1$
+                } else if ((bytik == ':') || (bytik == '/')) {
+                    if (component % 2 == 1) {
+                        // second byte of the component is omitted 
+                        // (it is the situation like: ... ABDC:AB:ABCD ...)
+                        throw new IOException(Messages.getString("security.18E", ip)); //$NON-NLS-1$
+                    }
+                    if (bytik == '/') {
+                        if (reading_second_bound) {
+                            // more than 2 bounds in the range
+                            throw new IOException(
+                                    Messages.getString("security.18E", ip)); //$NON-NLS-1$
+                        }
+                        if (component != 16) {
+                            // check the number of read components
+                            throw new IOException(Messages.getString("security.18F", ip)); //$NON-NLS-1$
+                        }
+                        reading_second_bound = true;
+                    }
+                    expect_delimiter = false;
+                    continue;
+                } else {
+                    throw new IOException(Messages.getString("security.18E", ip)); //$NON-NLS-1$
+                }
+                if (expect_delimiter) { // delimiter is expected but was not read
+                    throw new IOException(Messages.getString("security.18E", ip)); //$NON-NLS-1$
+                }
+                if (!second_hex) {
+                    // first half of byte has been read
+                    result[component] = (byte) (value << 4);
+                    second_hex = true;
+                } else {
+                    // second half of byte has been read
+                    result[component] = (byte)
+                        ((result[component] & 0xFF) | value);
+                    // delimiter is expected if 2 bytes were read
+                    expect_delimiter = (component % 2 == 1);
+                    second_hex = false;
+                    component++;
+                }
+            }
+            // check the correctness of the read address:
+            if (second_hex || (component % 2 == 1)) {
+                throw new IOException(Messages.getString("security.18E", ip)); //$NON-NLS-1$
+            }
+        }
+        return result;
+    }
+
+    
+    /**
+     * Helper method. Converts the byte array representation of ip address
+     * to the String.
+     * @param   ip :   byte array representation of ip address
+     *  If the length of byte array 4 then it represents an IP v4 
+     *  and the output String will be in the dotted quad form. 
+     *  If the length is 16 then it represents an IP v6 
+     *  and the output String will be returned in format "p1:p2:...:p8", 
+     *  where p1-p8 are hexadecimal values representing the eight 16-bit 
+     *  pieces of the address.
+     *  If the length is 8 or 32 then it represents an address range (RFC 1519)
+     *  and the output String will contain 2 IP address divided by "/"
+     * @return  String representation of ip address
+     */
+    public static String ipBytesToStr(byte[] ip) {
+        String result = ""; //$NON-NLS-1$
+        if (ip.length < 9) { // IP v4
+            for (int i=0; i<ip.length; i++) {
+                result += Integer.toString(ip[i] & 0xff);
+                if (i != ip.length-1) {
+                    result += (i == 3) ? "/": "."; //$NON-NLS-1$ //$NON-NLS-2$
+                }
+            }
+        } else {
+            for (int i=0; i<ip.length; i++) {
+                result += Integer.toHexString(0x00ff & ip[i]);
+                if ((i % 2 != 0) && (i != ip.length-1)) {
+                    result += (i == 15) ? "/": ":"; //$NON-NLS-1$ //$NON-NLS-2$
+                }
+            }
+        }
+        return result;
+    }
+ 
+    public static final ASN1Choice ASN1 = new ASN1Choice(new ASN1Type[] {
+           new ASN1Implicit(0, OtherName.ASN1), 
+           new ASN1Implicit(1, ASN1StringType.IA5STRING), 
+           new ASN1Implicit(2, ASN1StringType.IA5STRING),
+           new ASN1Implicit(3, ORAddress.ASN1),
+           new ASN1Implicit(4, Name.ASN1),
+           new ASN1Implicit(5, EDIPartyName.ASN1),
+           new ASN1Implicit(6, ASN1StringType.IA5STRING),
+           new ASN1Implicit(7, ASN1OctetString.getInstance()),
+           new ASN1Implicit(8, ASN1Oid.getInstance()) }) {
+
+        public Object getObjectToEncode(Object value) {
+            return ((GeneralName) value).name;
+        }
+        
+        public int getIndex(java.lang.Object object) {
+            return  ((GeneralName) object).tag;
+        }
+
+        public Object getDecodedObject(BerInputStream in) throws IOException {
+            GeneralName result;
+            switch (in.choiceIndex) {
+                case OTHER_NAME: // OtherName
+                    result = new GeneralName((OtherName) in.content);
+                    break;
+                case RFC822_NAME: // rfc822Name
+                case DNS_NAME: // dNSName
+                    result = new GeneralName(in.choiceIndex, (String) in.content);
+                    break;
+                case X400_ADDR:
+                    result = new GeneralName((ORAddress) in.content);
+                    break;
+                case DIR_NAME: // directoryName (X.500 Name)
+                    result = new GeneralName((Name) in.content);
+                    break;
+                case EDIP_NAME: // ediPartyName
+                    result = new GeneralName((EDIPartyName) in.content);
+                    break;
+                case UR_ID: // uniformResourceIdentifier
+                    String uri = (String) in.content;
+                    if (uri.indexOf(":") == -1) { //$NON-NLS-1$
+                        throw new IOException(
+                            Messages.getString("security.190", uri)); //$NON-NLS-1$
+                    }
+                    result = new GeneralName(in.choiceIndex, uri);
+                    break;
+                case IP_ADDR: // iPAddress
+                    result = new GeneralName((byte[]) in.content);
+                    break;
+                case REG_ID: // registeredID
+                    result = new GeneralName(in.choiceIndex, 
+                            ObjectIdentifier.toString((int[]) in.content));
+                    break;
+                default:
+                    throw new IOException(Messages.getString("security.191", in.choiceIndex)); //$NON-NLS-1$
+            }
+            result.encoding = in.getEncoded();
+            return result;
+        }
+    };
+    
+    // public static void printAsHex(int perLine,
+    //         String prefix,
+    //         String delimiter,
+    //         byte[] data) {
+    //     for (int i=0; i<data.length; i++) {
+    //         String tail = Integer.toHexString(0x000000ff & data[i]);
+    //         if (tail.length() == 1) {
+    //             tail = "0" + tail; 
+    //         }
+    //         System.out.print(prefix + "0x" + tail + delimiter);
+ 
+    //         if (((i+1)%perLine) == 0) {
+    //             System.out.println();
+    //         }
+    //     }
+    //     System.out.println();
+    // }
+
+    // public static void main(String[] args) {
+    //     System.out.println(">> "+new BigInteger(new byte[] {(byte)23, (byte)255}).toString(2));
+    //     System.out.println(ipBytesToStr(new byte[] {(byte)255, (byte)23, (byte)128, (byte)130}));
+    //     System.out.println(ipBytesToStr(new byte[] {(byte)255, (byte)23, (byte)128, (byte)130,
+    //                                                 (byte)255, (byte)23, (byte)128, (byte)130}));
+    //     System.out.println(ipBytesToStr(new byte[] {(byte)255, (byte)23, (byte)128, (byte)130,
+    //                                                 (byte)255, (byte)23, (byte)128, (byte)130,
+    //                                                 (byte)255, (byte)23, (byte)128, (byte)130,
+    //                                                 (byte)255, (byte)23, (byte)128, (byte)130}));
+    //     System.out.println(ipBytesToStr(new byte[] {(byte)255, (byte)23, (byte)128, (byte)130,
+    //                                                 (byte)255, (byte)23, (byte)128, (byte)130,
+    //                                                 (byte)255, (byte)23, (byte)128, (byte)130,
+    //                                                 (byte)255, (byte)23, (byte)128, (byte)130,
+    //                                                 (byte)255, (byte)23, (byte)128, (byte)130,
+    //                                                 (byte)255, (byte)23, (byte)128, (byte)130,
+    //                                                 (byte)255, (byte)23, (byte)128, (byte)130,
+    //                                                 (byte)255, (byte)23, (byte)128, (byte)130}));
+    //     ipStrToBytes("1.2.3.4");
+    //     ipStrToBytes("1.2.3.4/4.3.2.1");
+    //     printAsHex(8, "", " ", ipStrToBytes("ff17:8082:ff17:8082:ff17:8082:ff17:8082/ff17:8082:ff17:8082:ff17:8082:ff17:8082"));
+    // }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/GeneralNames.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/GeneralNames.java
new file mode 100644
index 0000000..0ad78df
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/GeneralNames.java
@@ -0,0 +1,181 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.harmony.security.asn1.ASN1SequenceOf;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with the GeneralNames structure which is a part of X.509 certificate
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *
+ * 
+ * <pre>
+ *   GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+ * </pre>
+ * 
+ * @see org.apache.harmony.security.x509.NameConstraints
+ * @see org.apache.harmony.security.x509.GeneralSubtree
+ */
+public class GeneralNames {
+
+    // the values of GeneralName
+    private List generalNames;
+    // the ASN.1 encoded form of GeneralNames
+    private byte[] encoding;
+    
+    /**
+     * Constructs an object representing the value of GeneralNames.
+     */
+    public GeneralNames() {
+        generalNames = new ArrayList();
+    }
+    
+    /**
+     * TODO
+     * @param   generalNames:   List
+     */
+    public GeneralNames(List generalNames) {
+        this.generalNames = generalNames;
+    }
+    
+    // 
+    // TODO
+    // @param   generalNames:   List
+    // @param   encoding:   byte[]
+    // 
+    private GeneralNames(List generalNames, byte[] encoding) {
+        this.generalNames = generalNames;
+        this.encoding = encoding;
+    }
+
+    /**
+     * Returns the list of values.
+     * @return  names
+     */
+    public List getNames() {
+        if ((generalNames == null) || (generalNames.size() == 0)) {
+            return null;
+        }
+        return new ArrayList(generalNames);
+    }
+
+    /**
+     * Returns the collection of pairs: (Integer (tag), Object (name value))*
+     * @return the collection of pairs: (Integer (tag), Object (name value))*
+     */
+    public List getPairsList() {
+        ArrayList result = new ArrayList();
+        if (generalNames == null) {
+            return result;
+        }
+        Iterator it = generalNames.iterator();
+        while (it.hasNext()) {
+            result.add(((GeneralName) it.next()).getAsList());
+        }
+        return result;
+    }
+
+    /**
+     * TODO
+     * @param   name:   GeneralName
+     * @return
+     */
+    public void addName(GeneralName name) {
+        encoding = null;
+        if (generalNames == null) {
+            generalNames = new ArrayList();
+        }
+        generalNames.add(name);
+    }
+
+    /* *
+     * TODO
+     * @param   name:   GeneralName
+     * @return
+     * 
+    public GeneralName getNameByTag(int tag) {
+        encoding = null;
+        if ((generalNames == null) || (generalNames.size() == 0)) {
+            return null;
+        }
+        for (int i=0; i<generalNames.size(); i++) {
+            if (((GeneralName) generalName.get(i)).getTag() == tag) {
+            }
+        }
+        generalNames.add(name);
+    }
+     */
+
+    /**
+     * Returns ASN.1 encoded form of this X.509 GeneralNames value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    /**
+     * Places the string representation of extension value
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        if (generalNames == null) {
+            return;
+        }
+        for (Iterator it=generalNames.iterator(); it.hasNext();) {
+            buffer.append(prefix);
+            buffer.append(it.next());
+            buffer.append('\n');
+        }
+    }
+
+    /**
+     * ASN.1 DER X.509 GeneralNames encoder/decoder class.
+     */
+    public static final ASN1Type ASN1 = new ASN1SequenceOf(GeneralName.ASN1) {
+
+        public Object getDecodedObject(BerInputStream in) {
+            return new GeneralNames((List)in.content, in.getEncoded());
+        }
+
+        public Collection getValues(Object object) {
+            GeneralNames gns = (GeneralNames) object;
+            return gns.generalNames;
+        }
+    };
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/GeneralSubtree.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/GeneralSubtree.java
new file mode 100644
index 0000000..155d1e7
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/GeneralSubtree.java
@@ -0,0 +1,178 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import org.apache.harmony.security.asn1.ASN1Implicit;
+import org.apache.harmony.security.asn1.ASN1Integer;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with the GeneralSubtree structure which is a part of X.509 certificate:
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ * 
+ * <pre>
+ * 
+ *   GeneralSubtree ::= SEQUENCE {
+ *        base                    GeneralName,
+ *        minimum         [0]     BaseDistance DEFAULT 0,
+ *        maximum         [1]     BaseDistance OPTIONAL }
+ * 
+ *   BaseDistance ::= INTEGER (0..MAX)
+ *  
+ * </pre>
+ * 
+ * @see org.apache.harmony.security.x509.NameConstraints
+ * @see org.apache.harmony.security.x509.GeneralName
+ */
+public class GeneralSubtree {
+
+    // the value of base field of the structure
+    private final GeneralName base;
+    // the value of minimum field of the structure
+    private final int minimum;
+    // the value of maximum field of the structure
+    private final int maximum;
+    // the ASN.1 encoded form of GeneralSubtree
+    private byte[] encoding;
+
+    /**
+     * TODO
+     * @param   base:   GeneralName
+     */
+    public GeneralSubtree(GeneralName base) {
+        this(base, 0, -1);
+    }
+    
+    /**
+     * TODO
+     * @param   base:   GeneralName
+     * @param   minimum:    int
+     */
+    public GeneralSubtree(GeneralName base, int minimum) {
+        this(base, minimum, -1);
+    }
+    
+    /**
+     * TODO
+     * @param   base:   GeneralName
+     * @param   minimum:    int
+     * @param   maximum:    int
+     */
+    public GeneralSubtree(GeneralName base, int minimum, int maximum) {
+        this.base = base;
+        this.minimum = minimum;
+        this.maximum = maximum;
+    }
+    
+    /**
+     * Returns the value of base field of the structure.
+     * @return  base
+     */
+    public GeneralName getBase() {
+        return base;
+    }
+
+    /**
+     * Returns the value of maximum field of the structure.
+     * @return  maximum
+     */
+    public int getMaximum() {
+        return maximum;
+    }
+
+    /**
+     * Returns the value of minimum field of the structure.
+     * @return  minimum
+     */
+    public int getMinimum() {
+        return minimum;
+    }
+
+    /**
+     * Returns ASN.1 encoded form of this X.509 GeneralSubtree value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    /**
+     * Places the string representation of extension value
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        buffer.append(prefix).append("General Subtree: [\n"); //$NON-NLS-1$
+        buffer.append(prefix).append("  base: ").append(base).append('\n'); //$NON-NLS-1$
+        buffer.append(prefix).append("  minimum: ") //$NON-NLS-1$
+            .append(minimum).append('\n');
+        if (maximum >= 0) {
+            buffer.append(prefix).append("  maximum: ") //$NON-NLS-1$
+                .append(maximum).append('\n');
+        }
+        buffer.append(prefix).append("]\n"); //$NON-NLS-1$
+    }
+
+    /**
+     * ASN.1 DER X.509 GeneralSubtree encoder/decoder class.
+     */
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
+            GeneralName.ASN1,
+            new ASN1Implicit(0, ASN1Integer.getInstance()), 
+            new ASN1Implicit(1, ASN1Integer.getInstance()) }) {
+        {
+            setDefault(new byte[] {0}, 1);  // minimum 0
+            setOptional(2);                 // maximum optional
+        }
+
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+            int maximum = -1; // is optional maximum missing?
+            if (values[2] != null) {
+                maximum = ASN1Integer.toIntValue(values[2]); // no!
+            }
+            return new GeneralSubtree((GeneralName) values[0],
+                    ASN1Integer.toIntValue(values[1]),
+                    maximum);
+        }
+
+        protected void getValues(Object object, Object[] values) {
+
+            GeneralSubtree gs = (GeneralSubtree) object;
+
+            values[0] = gs.base;
+            values[1] = ASN1Integer.fromIntValue(gs.minimum);
+            if (gs.maximum > -1) {
+                values[2] = ASN1Integer.fromIntValue(gs.maximum);
+            }
+        }
+    };
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/GeneralSubtrees.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/GeneralSubtrees.java
new file mode 100644
index 0000000..1f87f9a
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/GeneralSubtrees.java
@@ -0,0 +1,119 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.harmony.security.asn1.ASN1SequenceOf;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with the GeneralSubtrees structure which is a part of X.509 certificate:
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ * 
+ * <pre>
+ *   GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
+ * </pre>
+ * 
+ * @see org.apache.harmony.security.x509.NameConstraints
+ * @see org.apache.harmony.security.x509.GeneralSubtree
+ */
+
+public class GeneralSubtrees {
+
+    // the list of values of GeneralSubtrees
+    private List generalSubtrees;
+    // the ASN.1 encoded form of GeneralSubtrees
+    private byte[] encoding;
+    
+    /**
+     * Constructs an object representing the value of GeneralSubtrees.
+     */
+    public GeneralSubtrees() {}
+    
+    /**
+     * TODO
+     * @param   generalSubtrees:    List
+     */
+    public GeneralSubtrees(List generalSubtrees) {
+        // TODO: the size should not be less than one
+        this.generalSubtrees = generalSubtrees;
+    }
+    
+    /**
+     * Returns the list of values of subtrees.
+     * @return  subtrees
+     */
+    public List getSubtrees() {
+        return generalSubtrees;
+    }
+
+    /**
+     * TODO
+     * @param   subtree:    GeneralSubtree
+     * @return
+     */
+    public GeneralSubtrees addSubtree(GeneralSubtree subtree) {
+        encoding = null;
+        if (generalSubtrees == null) {
+            generalSubtrees = new ArrayList();
+        }
+        generalSubtrees.add(subtree);
+        return this;
+    }
+
+    /**
+     * Returns ASN.1 encoded form of this X.509 AlgorithmIdentifier value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    /**
+     * ASN.1 DER X.509 GeneralSubtrees encoder/decoder class.
+     */
+    public static final ASN1Type ASN1 = new ASN1SequenceOf(GeneralSubtree.ASN1) {
+
+        public Object getDecodedObject(BerInputStream in) {
+            return new GeneralSubtrees((List)in.content);
+        }
+
+        public Collection getValues(Object object) {
+            GeneralSubtrees gss = (GeneralSubtrees) object;
+            return (gss.generalSubtrees == null) 
+                ? new ArrayList() : gss.generalSubtrees;
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/InfoAccessSyntax.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/InfoAccessSyntax.java
new file mode 100644
index 0000000..7323124
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/InfoAccessSyntax.java
@@ -0,0 +1,135 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.harmony.security.asn1.ASN1SequenceOf;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work
+ * with the SubjectInfoAccessSyntax and AuthorityInfoAccessSyntax 
+ * which are a part of X.509 framework
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *  
+ *  SubjectInfoAccessSyntax  ::=
+ *      SEQUENCE SIZE (1..MAX) OF AccessDescriptions
+
+ *  AuthorityInfoAccessSyntax  ::=
+ *      SEQUENCE SIZE (1..MAX) OF AccessDescriptions
+ *  
+ *  AccessDescription  ::=  SEQUENCE {
+ *      accessMethod          OBJECT IDENTIFIER,
+ *      accessLocation        GeneralName  }
+ * 
+ */
+public class InfoAccessSyntax extends ExtensionValue {
+
+    private final List accessDescriptions;
+
+    public InfoAccessSyntax(List accessDescriptions) throws IOException {
+        this(accessDescriptions, null);
+    }
+
+    private InfoAccessSyntax(List accessDescriptions, byte[] encoding)
+            throws IOException {
+        if (accessDescriptions == null || accessDescriptions.isEmpty()) {
+            // "AccessDescriptions list is null or empty"
+            throw new IOException(Messages.getString("security.1A3")); //$NON-NLS-1$
+        }
+        this.accessDescriptions = accessDescriptions;
+        this.encoding = encoding;
+    }
+
+    public List getAccessDescriptions() {
+        return new ArrayList(accessDescriptions);
+    }
+    
+    /**
+     * Returns ASN.1 encoded form of this X.509 InfoAccessSyntax.
+     * @return a byte array containing ASN.1 encoded form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    public static InfoAccessSyntax decode(byte[] encoding) throws IOException {
+        return ((InfoAccessSyntax) ASN1.decode(encoding));
+    }
+
+    public String toString() {
+        StringBuffer res = new StringBuffer();
+        res.append("\n---- InfoAccessSyntax:"); //$NON-NLS-1$
+        if (accessDescriptions != null) {
+            for (Iterator it = accessDescriptions.iterator(); it.hasNext();) {
+                res.append('\n');
+                res.append(it.next());
+            }
+        }
+        res.append("\n---- InfoAccessSyntax END\n"); //$NON-NLS-1$
+        return res.toString();
+    }
+
+    /**
+     * Places the string representation of extension value
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        buffer.append(prefix).append("AccessDescriptions:\n"); //$NON-NLS-1$
+        if (accessDescriptions == null || accessDescriptions.isEmpty()) {
+            buffer.append("NULL\n"); //$NON-NLS-1$
+        } else {
+            Iterator itr = accessDescriptions.iterator();
+            while (itr.hasNext()) {
+                buffer.append(itr.next().toString());
+            }
+        }
+    }
+
+    
+    /**
+     * ASN.1 DER X.509 AuthorityInfoAccessSyntax and SubjectInfoAccessSyntax 
+     * encoder/decoder class.
+     */
+    public static final ASN1Type ASN1 = new ASN1SequenceOf(AccessDescription.ASN1) {
+
+        public Object getDecodedObject(BerInputStream in) throws IOException {
+            return new InfoAccessSyntax((List)in.content, in.getEncoded());
+        }
+
+        public Collection getValues(Object object) {
+            InfoAccessSyntax aias = (InfoAccessSyntax) object;
+            return aias.accessDescriptions;
+        }
+    };
+
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/InhibitAnyPolicy.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/InhibitAnyPolicy.java
new file mode 100644
index 0000000..724a76b
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/InhibitAnyPolicy.java
@@ -0,0 +1,85 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import org.apache.harmony.security.asn1.ASN1Integer;
+
+/**
+ * InhibitAnyPolicy Certificate Extension (OID = 2.5.29.54)
+ * Its ASN.1 notation is as follows:
+ * <pre>
+ *  id-ce-inhibitAnyPolicy OBJECT IDENTIFIER ::=  { id-ce 54 }
+ *
+ *  InhibitAnyPolicy ::= SkipCerts
+ *
+ *  SkipCerts ::= INTEGER (0..MAX)
+ * </pre>
+ * (as specified in RFC 3280 http://www.ietf.org/rfc/rfc3280.txt).
+ */
+public class InhibitAnyPolicy extends ExtensionValue {
+
+    // the value of the extension
+    private int skipCerts;
+
+    /**
+     * Create the object on the base of SkipCerts value.
+     */
+    public InhibitAnyPolicy(int skipCerts) {
+        this.skipCerts = skipCerts;
+    }
+
+    /**
+     * Creates an object on the base of its encoded form.
+     */
+    public InhibitAnyPolicy(byte[] encoding) throws IOException {
+        super(encoding);
+        this.skipCerts = new BigInteger((byte[])
+                ASN1Integer.getInstance().decode(encoding)).intValue();
+    }
+
+    /**
+     * Return the value of the extension.
+     */
+    public int getSkipCerts() {
+        return skipCerts;
+    }
+
+    /**
+     * Returns ASN.1 encoded form of the object.
+     * @return a byte array containing ASN.1 encoded form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1Integer.getInstance()
+                .encode(ASN1Integer.fromIntValue(skipCerts));
+        }
+        return encoding;
+    }
+
+    /**
+     * Places the string representation of extension value
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        buffer.append(prefix).append("Inhibit Any-Policy: ") //$NON-NLS-1$
+            .append(skipCerts).append('\n');
+    }
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/InvalidityDate.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/InvalidityDate.java
new file mode 100644
index 0000000..bc04caf
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/InvalidityDate.java
@@ -0,0 +1,87 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+import java.util.Date;
+
+import org.apache.harmony.security.asn1.ASN1GeneralizedTime;
+import org.apache.harmony.security.asn1.ASN1Type;
+
+/**
+ * CRL Entry's Invalidity Date Extension (OID = 2.5.29.24).
+ * <pre>
+ *   id-ce-invalidityDate OBJECT IDENTIFIER ::= { id-ce 24 }
+ *
+ *   invalidityDate ::=  GeneralizedTime
+ * </pre>
+ * (as specified in RFC 3280 http://www.ietf.org/rfc/rfc3280.txt)
+ */
+public class InvalidityDate extends ExtensionValue {
+
+    // invalidity date value
+    private final Date date;
+
+    /**
+     * Constructs the object on the base of the invalidity date value.
+     */
+    public InvalidityDate(Date date) {
+        this.date = date;
+    }
+
+    /**
+     * Constructs the object on the base of its encoded form.
+     */
+    public InvalidityDate(byte[] encoding) throws IOException {
+        super(encoding);
+        date = (Date) ASN1.decode(encoding);
+    }
+
+    /**
+     * Returns the invalidity date.
+     */
+    public Date getDate() {
+        return date;
+    }
+
+    /**
+     * Returns ASN.1 encoded form of this X.509 InvalidityDate value.
+     * @return a byte array containing ASN.1 encoded form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(date);
+        }
+        return encoding;
+    }
+
+    /**
+     * Places the string representation of extension value
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        buffer.append(prefix).append("Invalidity Date: [ ") //$NON-NLS-1$
+            .append(date).append(" ]\n"); //$NON-NLS-1$
+    }
+
+    /**
+     * ASN.1 Encoder/Decoder.
+     */
+    public static ASN1Type ASN1 = ASN1GeneralizedTime.getInstance();
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/IssuingDistributionPoint.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/IssuingDistributionPoint.java
new file mode 100644
index 0000000..aec57c3
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/IssuingDistributionPoint.java
@@ -0,0 +1,240 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.asn1.ASN1Boolean;
+import org.apache.harmony.security.asn1.ASN1Explicit;
+import org.apache.harmony.security.asn1.ASN1Implicit;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+
+/**
+ * CRL's Issuing Distribution Point Extension (OID = 2.5.29.28).
+ * <pre>
+ *   id-ce-issuingDistributionPoint OBJECT IDENTIFIER ::= { id-ce 28 }
+ *
+ *   issuingDistributionPoint ::= SEQUENCE {
+ *      distributionPoint          [0] DistributionPointName OPTIONAL,
+ *      onlyContainsUserCerts      [1] BOOLEAN DEFAULT FALSE,
+ *      onlyContainsCACerts        [2] BOOLEAN DEFAULT FALSE,
+ *      onlySomeReasons            [3] ReasonFlags OPTIONAL,
+ *      indirectCRL                [4] BOOLEAN DEFAULT FALSE,
+ *      onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE
+ *   }
+ * </pre>
+ * (as specified in RFC 3280 http://www.ietf.org/rfc/rfc3280.txt)
+ */
+public class IssuingDistributionPoint extends ExtensionValue {
+
+    // values of the fields of the structure
+    private DistributionPointName distributionPoint;
+    private boolean onlyContainsUserCerts = false;
+    private boolean onlyContainsCACerts = false;
+    private ReasonFlags onlySomeReasons;
+    private boolean indirectCRL = false;
+    private boolean onlyContainsAttributeCerts = false;
+
+    /**
+     * Constructs the object on the base of its distributionPoint and
+     * onlySomeReasons fields values.
+     */
+    public IssuingDistributionPoint(DistributionPointName distributionPoint,
+            ReasonFlags onlySomeReasons) {
+        this.distributionPoint = distributionPoint;
+        this.onlySomeReasons = onlySomeReasons;
+    }
+
+    /**
+     * Creates the extension object on the base of its encoded form.
+     */
+    public static IssuingDistributionPoint decode(byte[] encoding) 
+            throws IOException {
+        IssuingDistributionPoint idp =
+            (IssuingDistributionPoint) ASN1.decode(encoding);
+        idp.encoding = encoding;
+        return idp;
+    }
+
+    /**
+     * Sets the value of onlyContainsUserCerts field of the structure.
+     */
+    public void setOnlyContainsUserCerts(boolean onlyContainsUserCerts) {
+        this.onlyContainsUserCerts = onlyContainsUserCerts;
+    }
+
+    /**
+     * Sets the value of onlyContainsCACerts field of the structure.
+     */
+    public void setOnlyContainsCACerts(boolean onlyContainsCACerts) {
+        this.onlyContainsCACerts = onlyContainsCACerts;
+    }
+
+    /**
+     * Sets the value of indirectCRL field of the structure.
+     */
+    public void setIndirectCRL(boolean indirectCRL) {
+        this.indirectCRL = indirectCRL;
+    }
+
+    /**
+     * Sets the value of onlyContainsAttributeCerts field of the structure.
+     */
+    public void setOnlyContainsAttributeCerts(
+            boolean onlyContainsAttributeCerts) {
+        this.onlyContainsAttributeCerts = onlyContainsAttributeCerts;
+    }
+
+    /**
+     * Returns value of distributionPoint field of the structure.
+     */
+    public DistributionPointName getDistributionPoint() {
+        return distributionPoint;
+    }
+
+    /**
+     * Returns value of onlyContainsUserCerts field of the structure.
+     */
+    public boolean getOnlyContainsUserCerts() {
+        return onlyContainsUserCerts;
+    }
+
+    /**
+     * Returns value of onlyContainsCACerts field of the structure.
+     */
+    public boolean getOnlyContainsCACerts() {
+        return onlyContainsCACerts;
+    }
+
+    /**
+     * Returns value of onlySomeReasons field of the structure.
+     */
+    public ReasonFlags getOnlySomeReasons() {
+        return onlySomeReasons;
+    }
+
+    /**
+     * Returns value of indirectCRL field of the structure.
+     */
+    public boolean getIndirectCRL() {
+        return indirectCRL;
+    }
+
+    /**
+     * Returns value of onlyContainsAttributeCerts field of the structure.
+     */
+    public boolean getOnlyContainsAttributeCerts() {
+        return onlyContainsAttributeCerts;
+    }
+
+    /**
+     * Returns ASN.1 encoded form of this X.509 IssuingDistributionPoint value.
+     * @return a byte array containing ASN.1 encoded form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    /**
+     * Places the string representation of extension value
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        buffer.append(prefix).append("Issuing Distribution Point: [\n"); //$NON-NLS-1$
+        if (distributionPoint != null) {
+            distributionPoint.dumpValue(buffer, "  " + prefix); //$NON-NLS-1$
+        }
+        buffer.append(prefix).append("  onlyContainsUserCerts: ") //$NON-NLS-1$
+            .append(onlyContainsUserCerts).append('\n');
+        buffer.append(prefix).append("  onlyContainsCACerts: ") //$NON-NLS-1$
+            .append(onlyContainsCACerts).append('\n');
+        if (onlySomeReasons != null) {
+            onlySomeReasons.dumpValue(buffer, prefix + "  "); //$NON-NLS-1$
+        }
+        buffer.append(prefix).append("  indirectCRL: ") //$NON-NLS-1$
+            .append(indirectCRL).append('\n');
+        buffer.append(prefix).append("  onlyContainsAttributeCerts: ") //$NON-NLS-1$
+            .append(onlyContainsAttributeCerts).append('\n');
+    }
+
+    /**
+     * ASN.1 Encoder/Decoder.
+     */
+    public static ASN1Type ASN1 = new ASN1Sequence(
+            new ASN1Type[] {
+                // ASN.1 prohibits implicitly tagged CHOICE
+                new ASN1Explicit(0, DistributionPointName.ASN1),
+                new ASN1Implicit(1, ASN1Boolean.getInstance()),
+                new ASN1Implicit(2, ASN1Boolean.getInstance()),
+                new ASN1Implicit(3, ReasonFlags.ASN1),
+                new ASN1Implicit(4, ASN1Boolean.getInstance()),
+                new ASN1Implicit(5, ASN1Boolean.getInstance())
+            }) {
+        {
+            setOptional(0);
+            setOptional(3);
+            setDefault(Boolean.FALSE, 1);
+            setDefault(Boolean.FALSE, 2);
+            setDefault(Boolean.FALSE, 4);
+            setDefault(Boolean.FALSE, 5);
+        }
+
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+            IssuingDistributionPoint idp =
+                new IssuingDistributionPoint(
+                        (DistributionPointName) values[0],
+                        (ReasonFlags) values[3]);
+            idp.encoding = in.getEncoded();
+            if (values[1] != null) {
+                idp.setOnlyContainsUserCerts(
+                        ((Boolean) values[1]).booleanValue());
+            }
+            if (values[2] != null) {
+                idp.setOnlyContainsCACerts(
+                        ((Boolean) values[2]).booleanValue());
+            }
+            if (values[4] != null) {
+                idp.setIndirectCRL(
+                        ((Boolean) values[4]).booleanValue());
+            }
+            if (values[5] != null) {
+                idp.setOnlyContainsAttributeCerts(
+                        ((Boolean) values[5]).booleanValue());
+            }
+            return idp;
+        }
+
+        protected void getValues(Object object, Object[] values) {
+            IssuingDistributionPoint idp = (IssuingDistributionPoint) object;
+            values[0] = idp.distributionPoint;
+            values[1] = (idp.onlyContainsUserCerts) ? Boolean.TRUE : null;
+            values[2] = (idp.onlyContainsCACerts) ? Boolean.TRUE : null;
+            values[3] = idp.onlySomeReasons;
+            values[4] = (idp.indirectCRL) ? Boolean.TRUE : null;
+            values[5] = (idp.onlyContainsAttributeCerts) ? Boolean.TRUE : null;
+        }
+    };
+
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/KeyUsage.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/KeyUsage.java
new file mode 100644
index 0000000..e8983de
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/KeyUsage.java
@@ -0,0 +1,116 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.ASN1BitString;
+
+/**
+ * Key Usage Extension (OID = 2.5.29.15).
+ *
+ * The ASN.1 definition for Key Usage Extension is:
+ *
+ * <pre>
+ * id-ce-keyUsage OBJECT IDENTIFIER ::=  { id-ce 15 }
+ *
+ * KeyUsage ::= BIT STRING {
+ *     digitalSignature        (0),
+ *     nonRepudiation          (1),
+ *     keyEncipherment         (2),
+ *     dataEncipherment        (3),
+ *     keyAgreement            (4),
+ *     keyCertSign             (5),
+ *     cRLSign                 (6),
+ *     encipherOnly            (7),
+ *     decipherOnly            (8)
+ * }
+ * </pre>
+ * (as specified in RFC 3280 http://www.ietf.org/rfc/rfc3280.txt)
+ */
+public class KeyUsage extends ExtensionValue {
+
+    /**
+     * The names of the usages.
+     */
+    private static final String[] USAGES = {
+        "digitalSignature", //$NON-NLS-1$
+        "nonRepudiation", //$NON-NLS-1$
+        "keyEncipherment", //$NON-NLS-1$
+        "dataEncipherment", //$NON-NLS-1$
+        "keyAgreement", //$NON-NLS-1$
+        "keyCertSign", //$NON-NLS-1$
+        "cRLSign", //$NON-NLS-1$
+        "encipherOnly", //$NON-NLS-1$
+        "decipherOnly", //$NON-NLS-1$
+    };
+
+    // the value of extension
+    private final boolean[] keyUsage;
+
+    /**
+     * Creates the extension object corresponding to the given key usage.
+     */
+    public KeyUsage(boolean[] keyUsage) {
+        this.keyUsage = keyUsage;
+    }
+
+    /**
+     * Creates the extension object on the base of its encoded form.
+     */
+    public KeyUsage(byte[] encoding) throws IOException {
+        super(encoding);
+        this.keyUsage = (boolean[]) ASN1.decode(encoding);
+    }
+
+    public boolean[] getKeyUsage() {
+        return keyUsage;
+    }
+
+    /**
+     * Returns the encoded of the object.
+     * @return a byte array containing ASN.1 encoded form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(keyUsage);
+        }
+        return encoding;
+    }
+
+    /**
+     * Places the string representation of extension value
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        buffer.append(prefix).append("KeyUsage [\n"); //$NON-NLS-1$
+        for (int i=0; i<keyUsage.length; i++) {
+            if (keyUsage[i]) {
+                buffer.append(prefix).append("  ") //$NON-NLS-1$
+                    .append(USAGES[i]).append('\n');
+            }
+        }
+        buffer.append(prefix).append("]\n"); //$NON-NLS-1$
+    }
+
+    /**
+     * X.509 Extension value encoder/decoder.
+     */
+    private static final ASN1Type ASN1 = new ASN1BitString.ASN1NamedBitList(9);
+
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/NameConstraints.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/NameConstraints.java
new file mode 100644
index 0000000..2c347e8
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/NameConstraints.java
@@ -0,0 +1,327 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.harmony.security.asn1.ASN1Implicit;
+import org.apache.harmony.security.asn1.ASN1OctetString;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.internal.nls.Messages;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with the following structure which is a part of X.509 certificate
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ * 
+ * <pre>
+ * 
+ *   NameConstraints ::= SEQUENCE {
+ *        permittedSubtrees       [0]     GeneralSubtrees OPTIONAL,
+ *        excludedSubtrees        [1]     GeneralSubtrees OPTIONAL }
+ * 
+ *   GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
+ *  
+ * </pre>
+ * 
+ * 
+ * @see org.apache.harmony.security.x509.GeneralSubtree
+ * @see org.apache.harmony.security.x509.GeneralName
+ */
+public class NameConstraints extends ExtensionValue {
+
+    // the value of permittedSubtrees field of the structure
+    private final GeneralSubtrees permittedSubtrees;
+    // the value of excludedSubtrees field of the structure
+    private final GeneralSubtrees excludedSubtrees;
+    // the ASN.1 encoded form of NameConstraints
+    private byte[] encoding;
+
+    // helper fields
+    private ArrayList[] permitted_names;
+    private ArrayList[] excluded_names;
+
+    /**
+     * Default ctor
+     */
+    public NameConstraints() {
+        this(null, null);
+    }
+    
+    /**
+     * Constructs <code>NameConstrains</code> object
+     * @param   permittedSubtrees:  GeneralSubtrees
+     * @param   excludedSubtrees:   GeneralSubtrees
+     */
+    public NameConstraints(GeneralSubtrees permittedSubtrees, 
+                           GeneralSubtrees excludedSubtrees) {
+        if (permittedSubtrees != null) {
+            List ps = permittedSubtrees.getSubtrees();
+            if ((ps == null) || (ps.size() == 0)) {
+                throw 
+                    new IllegalArgumentException(Messages.getString("security.17D")); //$NON-NLS-1$
+            }
+        }
+        if (excludedSubtrees != null) {
+            List es = excludedSubtrees.getSubtrees();
+            if ((es == null) || (es.size() == 0)) {
+                throw 
+                    new IllegalArgumentException(Messages.getString("security.17E")); //$NON-NLS-1$
+            }
+        }
+        this.permittedSubtrees = permittedSubtrees;
+        this.excludedSubtrees = excludedSubtrees;
+    }
+
+    //
+    // Constructs NameConstrains object
+    // @param   permittedSubtrees:  GeneralSubtrees
+    // @param   excludedSubtrees:   GeneralSubtrees
+    // @param   encoding:   byte[]
+    //
+    private NameConstraints(GeneralSubtrees permittedSubtrees, 
+                            GeneralSubtrees excludedSubtrees, byte[] encoding) {
+        this(permittedSubtrees, excludedSubtrees);
+        this.encoding = encoding;
+    }
+
+    public static NameConstraints decode(byte[] encoding) throws IOException {
+        return (NameConstraints) ASN1.decode(encoding);
+    }
+    
+    /**
+     * Returns ASN.1 encoded form of this X.509 NameConstraints value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    // 
+    // Prepare the data structure to speed up the checking process.
+    // 
+    private void prepareNames() {
+        // array of lists with permitted General Names divided by type
+        permitted_names = new ArrayList[9];
+        if (permittedSubtrees != null) {
+            Iterator it =  permittedSubtrees.getSubtrees().iterator();
+            while (it.hasNext()) {
+                GeneralName name = ((GeneralSubtree) it.next()).getBase();
+                //System.out.println("PERMITTED: "+name);
+                int tag = name.getTag();
+                if (permitted_names[tag] == null) {
+                    permitted_names[tag] = new ArrayList();
+                }
+                permitted_names[tag].add(name);
+            }
+        }
+        // array of lists with excluded General Names divided by type
+        excluded_names = new ArrayList[9];
+        if (excludedSubtrees != null) {
+            Iterator it =  excludedSubtrees.getSubtrees().iterator();
+            while (it.hasNext()) {
+                GeneralName name = ((GeneralSubtree) it.next()).getBase();
+                //System.out.println("EXCLUDED: "+name);
+                int tag = name.getTag();
+                if (excluded_names[tag] == null) {
+                    excluded_names[tag] = new ArrayList();
+                }
+                excluded_names[tag].add(name);
+            }
+        }
+    }
+    
+    // 
+    // Returns the value of certificate extension
+    // 
+    private byte[] getExtensionValue(X509Certificate cert, String OID) {
+        try {
+            byte[] bytes = cert.getExtensionValue(OID);
+            if (bytes == null) {
+                return null;
+            }
+            return (byte[]) ASN1OctetString.getInstance().decode(bytes);
+        } catch (IOException e) {
+            return null;
+        }
+    }
+    
+    /**
+     * Apply the name restrictions specified by this NameConstraints
+     * instance to the subject distinguished name and subject alternative
+     * names of specified X509Certificate. Restrictions apply only
+     * if specified name form is present in the certificate.
+     * The restrictions are applied according the RFC 3280 
+     * (see 4.2.1.11 Name Constraints), excepting that restrictions are applied
+     * and to CA certificates, and to certificates which issuer and subject 
+     * names the same (i.e. method does not check if it CA's certificate or not,
+     * or if the names differ or not. This check if it is needed should be done 
+     * by caller before calling this method).
+     * @param   X509Certificate :   X.509 Certificate to be checked.
+     * @return  true, if the certificate is acceptable according
+     *          these NameConstraints restrictions, and false otherwise.
+     */
+    public boolean isAcceptable(X509Certificate cert) {
+        if (permitted_names == null) {
+            prepareNames();
+        }
+
+        byte[] bytes = getExtensionValue(cert, "2.5.29.17"); //$NON-NLS-1$
+        List names;
+        try {
+            names = (bytes == null) 
+                ? new ArrayList(1) // will check the subject field only
+                : ((GeneralNames) GeneralNames.ASN1.decode(bytes)).getNames();
+        } catch (IOException e) {
+            // the certificate is broken;
+            e.printStackTrace();
+            return false;
+        }
+        if ((excluded_names[4] != null) || (permitted_names[4] != null)) {
+            try {
+                names.add(new GeneralName(4, 
+                        cert.getSubjectX500Principal().getName()));
+            } catch (IOException e) {
+                // should never be happened
+            }
+        }
+        return isAcceptable(names);
+    }
+        
+    /**
+     * Check if this list of names is acceptable accoring to this
+     * NameConstraints object.
+     * @param   names:  List
+     * @return 
+     */
+    public boolean isAcceptable(List names) {
+        if (permitted_names == null) {
+            prepareNames();
+        }
+        
+        Iterator it = names.iterator();
+        // check map: shows which types of permitted alternative names are 
+        // presented in the certificate
+        boolean[] types_presented = new boolean[9];
+        // check map: shows if permitted name of presented type is found 
+        // among the certificate's alternative names
+        boolean[] permitted_found = new boolean[9];
+        while (it.hasNext()) {
+            GeneralName name = (GeneralName) it.next();
+            int type = name.getTag();
+            // search the name in excluded names
+            if (excluded_names[type] != null) {
+                for (int i=0; i<excluded_names[type].size(); i++) {
+                    if (((GeneralName) excluded_names[type].get(i))
+                            .isAcceptable(name)) {
+                        return false;
+                    }
+                }
+            }
+            // Search the name in permitted names
+            // (if we already found the name of such type between the alt
+            // names - we do not need to check others)
+            if ((permitted_names[type] != null) && (!permitted_found[type])) {
+                types_presented[type] = true;
+                for (int i=0; i<permitted_names[type].size(); i++) {
+                    if (((GeneralName) permitted_names[type].get(i))
+                            .isAcceptable(name)) {
+                        // found one permitted name of such type
+                        permitted_found[type] = true;
+                    }
+                }
+            }
+        }
+        for (int type=0; type<9; type++) {
+            if (types_presented[type] && !permitted_found[type]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Places the string representation of extension value
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        buffer.append(prefix).append("Name Constraints: [\n"); //$NON-NLS-1$
+        if (permittedSubtrees != null) {
+            buffer.append(prefix).append("  Permitted: [\n"); //$NON-NLS-1$
+            for (Iterator it=permittedSubtrees.getSubtrees().iterator();
+                    it.hasNext();) {
+                ((GeneralSubtree) it.next()).dumpValue(buffer, prefix + "    "); //$NON-NLS-1$
+            }
+            buffer.append(prefix).append("  ]\n"); //$NON-NLS-1$
+        }
+        if (excludedSubtrees != null) {
+            buffer.append(prefix).append("  Excluded: [\n"); //$NON-NLS-1$
+            for (Iterator it=excludedSubtrees.getSubtrees().iterator();
+                    it.hasNext();) {
+                ((GeneralSubtree) it.next()).dumpValue(buffer, prefix + "    "); //$NON-NLS-1$
+            }
+            buffer.append(prefix).append("  ]\n"); //$NON-NLS-1$
+        }
+        buffer.append('\n').append(prefix).append("]\n"); //$NON-NLS-1$
+    }
+    
+    /**
+     * X.509 NameConstraints encoder/decoder.
+     */
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
+            new ASN1Implicit(0, GeneralSubtrees.ASN1), 
+            new ASN1Implicit(1, GeneralSubtrees.ASN1) }) {
+        {
+            setOptional(0);
+            setOptional(1);
+        }
+
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+            return new NameConstraints(
+                    (GeneralSubtrees) values[0], 
+                    (GeneralSubtrees) values[1],
+                    in.getEncoded());
+        }
+
+        protected void getValues(Object object, Object[] values) {
+
+            NameConstraints nc = (NameConstraints) object;
+
+            values[0] = nc.permittedSubtrees;
+            values[1] = nc.excludedSubtrees;
+        }
+    };
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/ORAddress.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/ORAddress.java
new file mode 100644
index 0000000..0e3bf98
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/ORAddress.java
@@ -0,0 +1,93 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with the ORAddress structure which is a part of X.509 certificate:
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *
+ * <pre>
+ * ORAddress ::= SEQUENCE {
+ *   built-in-standard-attributes BuiltInStandardAttributes,
+ *   built-in-domain-defined-attributes
+ *                   BuiltInDomainDefinedAttributes OPTIONAL,
+ *   extension-attributes ExtensionAttributes OPTIONAL 
+ * }
+ * </pre>
+ *
+ * TODO: this class needs to be finished.
+ */
+public class ORAddress {
+
+    // the ASN.1 encoded form of ORAddress
+    private byte[] encoding;
+
+    /**
+     * TODO
+     */
+    public ORAddress() {}
+    
+    /**
+     * Returns ASN.1 encoded form of this X.509 ORAddress value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    /**
+     * ASN.1 DER X.509 ORAddress encoder/decoder class.
+     */
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
+            new ASN1Sequence(new ASN1Type[] {}) {
+                protected Object getDecodedObject(Object[] values) {
+                    return null;
+                }
+
+                protected void getValues(Object object, Object[] values) {
+                }
+            }}) {
+
+        protected Object getDecodedObject(BerInputStream in) {
+            return new ORAddress();
+        }
+
+        private final Object foo = new Object();  //$NON-LOCK-1$
+
+        protected void getValues(Object object, Object[] values) {
+            values[0] = foo;
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/OtherName.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/OtherName.java
new file mode 100644
index 0000000..150e81e
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/OtherName.java
@@ -0,0 +1,126 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import org.apache.harmony.security.asn1.ASN1Any;
+import org.apache.harmony.security.asn1.ASN1Explicit;
+import org.apache.harmony.security.asn1.ASN1Oid;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.asn1.ObjectIdentifier;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with OtherName structure which is a subpart of GeneralName
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *   
+ * <pre>
+ *   OtherName ::= SEQUENCE {
+ *        type-id    OBJECT IDENTIFIER,
+ *        value      [0] EXPLICIT ANY DEFINED BY type-id 
+ *   }
+ * </pre>
+ */
+public class OtherName {
+    // the value of typeID field of the structure
+    private String typeID;
+    // the value of value field of the structure
+    private byte[] value;
+    // the ASN.1 encoded form of OtherName
+    private byte[] encoding;
+    
+    /**
+     * TODO
+     * @param   typeID: String
+     * @param   value:  byte[]
+     */
+    public OtherName(String typeID, byte[] value) {
+        this(typeID, value, null);
+    }
+
+    // 
+    // TODO
+    // @param   typeID: String
+    // @param   value:  byte[]
+    // @param   encoding:   byte[]
+    // 
+    private OtherName(String typeID, byte[] value, byte[] encoding) {
+        this.typeID = typeID;
+        this.value = value;
+        this.encoding = encoding;
+    }
+        
+    /**
+     * Returns the value of typeID field of the structure.
+     * @return  typeID
+     */
+    public String getTypeID() {
+        return typeID;
+    }
+
+    /**
+     * Returns the value of value field of the structure.
+     * @return  value
+     */
+    public byte[] getValue() {
+        return value;
+    }
+    
+    /**
+     * Returns ASN.1 encoded form of this X.509 OtherName value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    /**
+     * ASN.1 DER X.509 OtherName encoder/decoder class.
+     */
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
+            ASN1Oid.getInstance(), 
+            new ASN1Explicit(0, ASN1Any.getInstance()) }) {
+
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+            return new OtherName(ObjectIdentifier.toString((int[]) values[0]),
+                    (byte[]) values[1], in.getEncoded());
+        }
+
+        protected void getValues(Object object, Object[] values) {
+
+            OtherName on = (OtherName) object;
+
+            values[0] = ObjectIdentifier.toIntArray(on.typeID);
+            values[1] = on.value;
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/PolicyConstraints.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/PolicyConstraints.java
new file mode 100644
index 0000000..7a6f54b
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/PolicyConstraints.java
@@ -0,0 +1,176 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov, Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+import org.apache.harmony.security.asn1.ASN1Implicit;
+import org.apache.harmony.security.asn1.ASN1Integer;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with PolicyConstraints structure which is a part of X.509 certificate
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ * 
+ * <pre>
+ *
+ *  PolicyConstraints ::= SEQUENCE {
+ *       requireExplicitPolicy           [0] SkipCerts OPTIONAL,
+ *       inhibitPolicyMapping            [1] SkipCerts OPTIONAL }
+ *
+ *  SkipCerts ::= INTEGER (0..MAX)
+ *
+ * </pre>
+ * 
+ * TODO: This class is not fully implemented.
+ *
+ * @see org.apache.harmony.security.x509.GeneralSubtree
+ * @see org.apache.harmony.security.x509.GeneralName
+ */
+public class PolicyConstraints extends ExtensionValue {
+
+    // the value of requireExplicitPolicy field of the structure
+    private final BigInteger requireExplicitPolicy;
+    // the value of inhibitPolicyMapping field of the structure
+    private final BigInteger inhibitPolicyMapping;
+    // the ASN.1 encoded form of PolicyConstraints;
+    private byte[] encoding;
+
+    /**
+     * TODO
+     */
+    public PolicyConstraints() {
+        this(null, null);
+    }
+    
+    /**
+     * TODO
+     * @param   requireExplicitPolicy:  GeneralSubtrees
+     * @param   inhibitPolicyMapping:   GeneralSubtrees
+     */
+    public PolicyConstraints(BigInteger requireExplicitPolicy,
+            BigInteger inhibitPolicyMapping) {
+        this.requireExplicitPolicy = requireExplicitPolicy;
+        this.inhibitPolicyMapping = inhibitPolicyMapping;
+    }
+
+    /**
+     * TODO
+     * @param   requireExplicitPolicy:  GeneralSubtrees
+     * @param   inhibitPolicyMapping:   GeneralSubtrees
+     */
+    public PolicyConstraints(int requireExplicitPolicy,
+            int inhibitPolicyMapping) {
+        this.requireExplicitPolicy = BigInteger.valueOf(requireExplicitPolicy);
+        this.inhibitPolicyMapping = BigInteger.valueOf(inhibitPolicyMapping);
+    }
+
+    public PolicyConstraints(byte[] encoding) throws IOException {
+        super(encoding);
+        PolicyConstraints pc = (PolicyConstraints) ASN1.decode(encoding);
+        this.requireExplicitPolicy = pc.requireExplicitPolicy;
+        this.inhibitPolicyMapping = pc.inhibitPolicyMapping;
+    }
+
+    //
+    // TODO
+    // @param   requireExplicitPolicy:  GeneralSubtrees
+    // @param   inhibitPolicyMapping:   GeneralSubtrees
+    // @param   encoding:   byte[]
+    //
+    private PolicyConstraints(BigInteger requireExplicitPolicy, 
+                            BigInteger inhibitPolicyMapping, byte[] encoding) {
+        this(requireExplicitPolicy, inhibitPolicyMapping);
+        this.encoding = encoding;
+    }
+    
+    /**
+     * Returns ASN.1 encoded form of this X.509 PolicyConstraints value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    /**
+     * Places the string representation of extension value 
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        buffer.append(prefix).append("PolicyConstraints: [\n"); //$NON-NLS-1$
+        if (requireExplicitPolicy != null) {
+            buffer.append(prefix).append("  requireExplicitPolicy: ") //$NON-NLS-1$
+                .append(requireExplicitPolicy).append('\n');
+        }
+        if (inhibitPolicyMapping != null) {
+            buffer.append(prefix).append("  inhibitPolicyMapping: ") //$NON-NLS-1$
+                .append(inhibitPolicyMapping).append('\n');
+        }
+        buffer.append(prefix).append("]\n"); //$NON-NLS-1$
+    }
+
+    /**
+     * X.509 PolicyConstraints encoder/decoder.
+     */
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
+            new ASN1Implicit(0, ASN1Integer.getInstance()), 
+            new ASN1Implicit(1, ASN1Integer.getInstance()) }) {
+        {
+            setOptional(0);
+            setOptional(1);
+        }
+
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+            BigInteger requireExplicitPolicy = null;
+            BigInteger inhibitPolicyMapping = null;
+            if (values[0] != null) {
+                requireExplicitPolicy = new BigInteger((byte[]) values[0]);
+            }
+            if (values[1] != null) {
+                inhibitPolicyMapping = new BigInteger((byte[]) values[1]);
+            }
+            return new PolicyConstraints(
+                requireExplicitPolicy, inhibitPolicyMapping,
+                    in.getEncoded());
+        }
+
+        protected void getValues(Object object, Object[] values) {
+
+            PolicyConstraints pc = (PolicyConstraints) object;
+
+            values[0] = pc.requireExplicitPolicy.toByteArray();
+            values[1] = pc.inhibitPolicyMapping.toByteArray();
+        }
+    };
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/PolicyInformation.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/PolicyInformation.java
new file mode 100644
index 0000000..bb51e29
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/PolicyInformation.java
@@ -0,0 +1,118 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import org.apache.harmony.security.asn1.ASN1Any;
+import org.apache.harmony.security.asn1.ASN1Oid;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.asn1.ObjectIdentifier;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with PolicyInformation structure which is a subpart of certificatePolicies
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *   
+ * <pre>
+ *  PolicyInformation ::= SEQUENCE {
+ *       policyIdentifier   CertPolicyId,
+ *       policyQualifiers   SEQUENCE SIZE (1..MAX) OF
+ *                               PolicyQualifierInfo OPTIONAL 
+ *  }
+ * </pre>
+ * 
+ * TODO: This class is not fully implemented, implemented only work
+ * with OIDs.
+ */
+
+public class PolicyInformation {
+
+    // the value of policyIdentifier field of the structure
+    private String policyIdentifier;
+    // the ASN.1 encoded form of PolicyInformation
+    private byte[] encoding;
+    
+    /**
+     * TODO
+     * @param   policyIdentifier:   String
+     */
+    public PolicyInformation(String policyIdentifier) {
+        this.policyIdentifier = policyIdentifier;
+    }
+
+    /**
+     * Returns the value of policyIdentifier field of the structure.
+     * @return  policyIdentifier
+     */
+    public String getPolicyIdentifier() {
+        return policyIdentifier;
+    }
+
+    /**
+     * Returns ASN.1 encoded form of this X.509 PolicyInformation value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    /**
+     * Places the string representation of extension value 
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer) {
+        buffer.append("Policy Identifier [") //$NON-NLS-1$
+            .append(policyIdentifier).append(']');
+    }
+
+    /**
+     * ASN.1 DER X.509 PolicyInformation encoder/decoder class.
+     */
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(
+            new ASN1Type[] { ASN1Oid.getInstance(), ASN1Any.getInstance() }) {
+        {
+            setOptional(1);
+        }
+
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+            return new PolicyInformation(ObjectIdentifier
+                    .toString((int[]) values[0]));
+        }
+
+        protected void getValues(Object object, Object[] values) {
+
+            PolicyInformation pi = (PolicyInformation) object;
+
+            values[0] = ObjectIdentifier.toIntArray(pi.policyIdentifier);
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/PolicyQualifierInfo.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/PolicyQualifierInfo.java
new file mode 100644
index 0000000..1cc672a
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/PolicyQualifierInfo.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import org.apache.harmony.security.asn1.ASN1Any;
+import org.apache.harmony.security.asn1.ASN1Oid;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+
+
+/**
+/**
+ * The class encapsulates the ASN.1 DER decoding work 
+ * with PolicyQualifierInfo structure
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *   
+ * <pre>
+ *    PolicyQualifierInfo ::= SEQUENCE {
+ *        policyQualifierId  PolicyQualifierId,
+ *        qualifier          ANY DEFINED BY policyQualifierId }
+ *
+ *    PolicyQualifierId ::=
+ *        OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice )
+ *
+ * </pre>
+ * 
+ */
+public class PolicyQualifierInfo {
+    // Contains only ASN1 DER decoder currently
+    public static final ASN1Sequence ASN1 =
+        new ASN1Sequence(new ASN1Type[] {ASN1Oid.getInstance(), ASN1Any.getInstance()}) {
+    };
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/PrivateKeyUsagePeriod.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/PrivateKeyUsagePeriod.java
new file mode 100644
index 0000000..417479a
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/PrivateKeyUsagePeriod.java
@@ -0,0 +1,133 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import java.util.Date;
+
+import org.apache.harmony.security.asn1.ASN1GeneralizedTime;
+import org.apache.harmony.security.asn1.ASN1Implicit;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with the following certificate extension (OID: 2.5.29.16)
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *
+ * <pre>
+ * PrivateKeyUsagePeriod ::= SEQUENCE {
+ *      notBefore       [0]     GeneralizedTime OPTIONAL,
+ *      notAfter        [1]     GeneralizedTime OPTIONAL 
+ * }
+ * </pre>
+ */
+public class PrivateKeyUsagePeriod {
+
+    // the value of notBeforeDate field of the structure
+    private final Date notBeforeDate;
+    // the value of notAfterDate field of the structure
+    private final Date notAfterDate;
+    // the ASN.1 encoded form of PrivateKeyUsagePeriod
+    private byte[] encoding;
+
+    /**
+     * TODO
+     * @param   notBeforeDate:  Date
+     * @param   notAfterDate:   Date
+     */
+    public PrivateKeyUsagePeriod(Date notBeforeDate, Date notAfterDate) {
+        this(notBeforeDate, notAfterDate, null); 
+    }
+
+    // 
+    // TODO
+    // @param   notBeforeDate:  Date
+    // @param   notAfterDate:   Date
+    // @param   encoding:   byte[]
+    // 
+    private PrivateKeyUsagePeriod(Date notBeforeDate, 
+                                  Date notAfterDate, byte[] encoding) {
+        this.notBeforeDate = notBeforeDate;
+        this.notAfterDate = notAfterDate;
+        this.encoding = encoding;
+    }
+        
+    /**
+     * Returns the value of notBefore field of the structure.
+     * @return  notBefore
+     */
+    public Date getNotBefore() {
+        return notBeforeDate;
+    }
+
+    /**
+     * Returns the value of notAfter field of the structure.
+     * @return  notAfter
+     */
+    public Date getNotAfter() {
+        return notAfterDate;
+    }
+    
+    /**
+     * Returns ASN.1 encoded form of this X.509 PrivateKeyUsagePeriod value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    /**
+     * ASN.1 DER X.509 PrivateKeyUsagePeriod encoder/decoder class.
+     */
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
+            new ASN1Implicit(0, ASN1GeneralizedTime.getInstance()), 
+            new ASN1Implicit(1, ASN1GeneralizedTime.getInstance()) }) {
+        {
+            setOptional(0);
+            setOptional(1);
+        }
+
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[])in.content;
+            return 
+                new PrivateKeyUsagePeriod((Date) values[0], (Date) values[1],
+                        in.getEncoded());
+        }
+
+        protected void getValues(Object object, Object[] values) {
+
+            PrivateKeyUsagePeriod pkup = (PrivateKeyUsagePeriod) object;
+
+            values[0] = pkup.notBeforeDate;
+            values[1] = pkup.notAfterDate;
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/ReasonCode.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/ReasonCode.java
new file mode 100644
index 0000000..26b4acc
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/ReasonCode.java
@@ -0,0 +1,133 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+
+import org.apache.harmony.security.asn1.ASN1Enumerated;
+import org.apache.harmony.security.asn1.ASN1Type;
+
+/**
+ * CRL Entry's Reason Code Extension (OID = 2.5.29.21).
+ * <pre>
+ *  id-ce-cRLReason OBJECT IDENTIFIER ::= { id-ce 21 }
+ *
+ *  -- reasonCode ::= { CRLReason }
+ *  CRLReason ::= ENUMERATED {
+ *       unspecified             (0),
+ *       keyCompromise           (1),
+ *       cACompromise            (2),
+ *       affiliationChanged      (3),
+ *       superseded              (4),
+ *       cessationOfOperation    (5),
+ *       certificateHold         (6),
+ *       removeFromCRL           (8),
+ *       privilegeWithdrawn      (9),
+ *       aACompromise           (10)
+ *  }
+ * </pre>
+ * (as specified in RFC 3280 http://www.ietf.org/rfc/rfc3280.txt)
+ */
+public class ReasonCode extends ExtensionValue {
+
+    // predefined reason code values
+    public static final byte UNSPECIFIED = 0;
+    public static final byte KEY_COMPROMISE = 1;
+    public static final byte CA_COMPROMISE = 2;
+    public static final byte AFFILIATION_CHANGED = 3;
+    public static final byte SUPERSEDED = 4;
+    public static final byte CESSATION_OF_OPERATION = 5;
+    public static final byte CERTIFICATE_HOLD = 6;
+    public static final byte REMOVE_FROM_CRL = 8;
+    public static final byte PRIVILEGE_WITHDRAWN = 9;
+    public static final byte AA_COMPROMISE = 10;
+
+    // the reason code value
+    private final byte code;
+
+    public ReasonCode(byte code) {
+        this.code = code;
+    }
+
+    public ReasonCode(byte[] encoding) throws IOException {
+        super(encoding);
+        this.code = ((byte[]) ASN1.decode(encoding))[0];
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    /**
+     * Returns ASN.1 encoded form of this X.509 ReasonCode value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(new byte[] {(byte) code});
+        }
+        return encoding;
+    }
+
+    /**
+     * Places the string representation of extension value
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        buffer.append(prefix).append("Reason Code: [ "); //$NON-NLS-1$
+        switch (code) {
+            case UNSPECIFIED:
+                buffer.append("unspecified"); //$NON-NLS-1$
+                break;
+            case KEY_COMPROMISE:
+                buffer.append("keyCompromise"); //$NON-NLS-1$
+                break;
+            case CA_COMPROMISE:
+                buffer.append("cACompromise"); //$NON-NLS-1$
+                break;
+            case AFFILIATION_CHANGED:
+                buffer.append("affiliationChanged"); //$NON-NLS-1$
+                break;
+            case SUPERSEDED:
+                buffer.append("superseded"); //$NON-NLS-1$
+                break;
+            case CESSATION_OF_OPERATION:
+                buffer.append("cessationOfOperation"); //$NON-NLS-1$
+                break;
+            case CERTIFICATE_HOLD:
+                buffer.append("certificateHold"); //$NON-NLS-1$
+                break;
+            case REMOVE_FROM_CRL:
+                buffer.append("removeFromCRL"); //$NON-NLS-1$
+                break;
+            case PRIVILEGE_WITHDRAWN:
+                buffer.append("privilegeWithdrawn"); //$NON-NLS-1$
+                break;
+            case AA_COMPROMISE:
+                buffer.append("aACompromise"); //$NON-NLS-1$
+                break;
+        }
+        buffer.append(" ]\n"); //$NON-NLS-1$
+    }
+
+    /**
+     * ASN.1 Encoder/Decoder.
+     */
+    public static ASN1Type ASN1 = ASN1Enumerated.getInstance();
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/ReasonFlags.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/ReasonFlags.java
new file mode 100644
index 0000000..6f72dc7
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/ReasonFlags.java
@@ -0,0 +1,112 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+
+import org.apache.harmony.security.asn1.ASN1BitString;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.asn1.BerOutputStream;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with the following part of X.509 CRL
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *
+ * <pre>
+ *  ReasonFlags ::= BIT STRING {
+ *        unused                  (0),
+ *        keyCompromise           (1),
+ *        cACompromise            (2),
+ *        affiliationChanged      (3),
+ *        superseded              (4),
+ *        cessationOfOperation    (5),
+ *        certificateHold         (6),
+ *        privilegeWithdrawn      (7),
+ *        aACompromise            (8) 
+ *  }
+ *  </pre>
+ */
+public class ReasonFlags {
+    
+    /**
+     * The names of the reasons.
+     */
+    public static final String[] REASONS = {
+        "unused", //$NON-NLS-1$
+        "keyCompromise", //$NON-NLS-1$
+        "cACompromise", //$NON-NLS-1$
+        "affiliationChanged", //$NON-NLS-1$
+        "superseded", //$NON-NLS-1$
+        "cessationOfOperation", //$NON-NLS-1$
+        "certificateHold", //$NON-NLS-1$
+        "privilegeWithdrawn", //$NON-NLS-1$
+        "aACompromise" //$NON-NLS-1$
+    };
+
+    // the value of extension
+    private boolean[] flags;
+    
+    /**
+     * Creates the extension object corresponding to the given flags.
+     */
+    public ReasonFlags(boolean[] flags) {
+        this.flags = flags;
+    }
+
+    /**
+     * Places the string representation of extension value
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        buffer.append(prefix);
+        buffer.append("ReasonFlags [\n"); //$NON-NLS-1$
+        for (int i=0; i<flags.length; i++) {
+            if (flags[i]) {
+                buffer.append(prefix).append("  ") //$NON-NLS-1$
+                    .append(REASONS[i]).append('\n');
+            }
+        }
+        buffer.append(prefix);
+        buffer.append("]\n"); //$NON-NLS-1$
+    }
+    
+    /**
+     * ASN.1 Encoder/Decoder.
+     */
+    public static ASN1BitString ASN1 = 
+                            new ASN1BitString.ASN1NamedBitList(REASONS.length) {
+        public Object getDecodedObject(BerInputStream in) throws IOException {
+            return new ReasonFlags((boolean[]) super.getDecodedObject(in));
+        }
+        
+        public void setEncodingContent(BerOutputStream out) {
+            out.content = ((ReasonFlags) out.content).flags;
+            super.setEncodingContent(out);
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/SubjectKeyIdentifier.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/SubjectKeyIdentifier.java
new file mode 100644
index 0000000..4437b29
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/SubjectKeyIdentifier.java
@@ -0,0 +1,83 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+
+import org.apache.harmony.security.asn1.ASN1OctetString;
+import org.apache.harmony.security.utils.Array;
+
+/**
+ * Subject Key Identifier Extension (OID = 2.5.29.14).
+ *
+ * The ASN.1 definition for extension is:
+ *
+ * <pre>
+ *  id-ce-subjectKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 14 }
+ *
+ *  SubjectKeyIdentifier ::= KeyIdentifier
+ *
+ *  KeyIdentifier ::= OCTET STRING
+ * </pre>
+ * (as specified in RFC 3280 http://www.ietf.org/rfc/rfc3280.txt)
+ */
+public class SubjectKeyIdentifier extends ExtensionValue {
+
+    // the value of key identifier
+    private final byte[] keyIdentifier;
+
+    /**
+     * Creates the object on the base of the value of key identifier.
+     */
+    public SubjectKeyIdentifier(byte[] keyIdentifier) {
+        this.keyIdentifier = keyIdentifier;
+    }
+
+    /**
+     * Creates an object on the base of its encoded form.
+     */
+    public static SubjectKeyIdentifier decode(byte[] encoding)
+            throws IOException {
+        SubjectKeyIdentifier res = new SubjectKeyIdentifier((byte[])
+                ASN1OctetString.getInstance().decode(encoding));
+        res.encoding = encoding;
+        return res;
+    }
+
+    /**
+     * Returns ASN.1 encoded form of extension.
+     * @return a byte array containing ASN.1 encoded form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1OctetString.getInstance().encode(keyIdentifier);
+        }
+        return encoding;
+    }
+
+    /**
+     * Places the string representation of extension value
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer, String prefix) {
+        buffer.append(prefix).append("SubjectKeyIdentifier: [\n"); //$NON-NLS-1$
+        buffer.append(Array.toString(keyIdentifier, prefix));
+        buffer.append(prefix).append("]\n"); //$NON-NLS-1$
+    }
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/SubjectPublicKeyInfo.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/SubjectPublicKeyInfo.java
new file mode 100644
index 0000000..852b3ce
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/SubjectPublicKeyInfo.java
@@ -0,0 +1,187 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+
+import org.apache.harmony.security.asn1.ASN1BitString;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.asn1.BitString;
+import org.apache.harmony.security.utils.AlgNameMapper;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work
+ * with the following structure which is a part of X.509 certificate
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *
+ * <pre>
+ *  SubjectPublicKeyInfo  ::=  SEQUENCE  {
+ *      algorithm            AlgorithmIdentifier,
+ *      subjectPublicKey     BIT STRING  
+ *  }
+ * </pre>
+ */
+public class SubjectPublicKeyInfo {
+
+    // the value of algorithmID field of the structure
+    private AlgorithmIdentifier algorithmID;
+    // the value of subjectPublicKey field of the structure
+    private byte[] subjectPublicKey;
+    // the public key corresponding to this SubjectPublicKeyInfo
+    private PublicKey publicKey;
+    // the value of unusedBits field of the structure
+    private int unusedBits;
+    // the ASN.1 encoded form of SubjectPublicKeyInfo
+    private byte[] encoding;
+    
+    /**
+     * TODO
+     * @param   algID:  AlgorithmIdentifier
+     * @param   subjectPublicKey:   byte[]
+     */
+    public SubjectPublicKeyInfo(AlgorithmIdentifier algID, 
+                                byte[] subjectPublicKey) { 
+        this(algID, subjectPublicKey, 0);
+    }
+
+    /**
+     * TODO
+     * @param   algID:  AlgorithmIdentifier
+     * @param   subjectPublicKey:   byte[]
+     * @param   unused: int
+     */
+    public SubjectPublicKeyInfo(AlgorithmIdentifier algID, 
+                                byte[] subjectPublicKey, int unused) {
+        this(algID, subjectPublicKey, 0, null);
+    }
+
+    // 
+    // TODO
+    // @param   algID:  AlgorithmIdentifier
+    // @param   subjectPublicKey:   byte[]
+    // @param   unused: int
+    // @param   encoding:   byte[]
+    // 
+    private SubjectPublicKeyInfo(AlgorithmIdentifier algID, 
+                                 byte[] subjectPublicKey, int unused, 
+                                 byte[] encoding) {
+        this.algorithmID = algID;
+        this.subjectPublicKey = subjectPublicKey;
+        this.unusedBits = unused;
+        this.encoding = encoding;
+    }
+
+    /**
+     * Returns the value of algorithmIdentifier field of the structure.
+     * @return  algorithmIdentifier
+     */
+    public AlgorithmIdentifier getAlgorithmIdentifier() {
+        return algorithmID;
+    }
+
+    /**
+     * Returns the value of subjectPublicKey field of the structure.
+     * @return  subjectPublicKey
+     */
+    public byte[] getSubjectPublicKey() {
+        return subjectPublicKey;
+    }
+
+    /**
+     * Returns the value of unusedBits field of the structure.
+     * @return  unusedBits
+     */
+    public int getUnusedBits() {
+        return unusedBits;
+    }
+
+    /**
+     * Returns ASN.1 encoded form of this X.509 SubjectPublicKeyInfo value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    /**
+     * Returns The PublicKey corresponding to this SubjectPublicKeyInfo
+     * instance.
+     * @return public key corresponding to this SubjectPublicKeyInfo.
+     */
+    public PublicKey getPublicKey() {
+        if (publicKey == null) {
+            String alg_oid = algorithmID.getAlgorithm();
+            try {
+                String alg = 
+                    AlgNameMapper.map2AlgName(alg_oid);
+                
+                if (alg == null) {
+                    alg = alg_oid;
+                }
+                publicKey = KeyFactory.getInstance(alg)
+                    .generatePublic(new X509EncodedKeySpec(getEncoded()));
+            } catch (InvalidKeySpecException e) {
+            } catch (NoSuchAlgorithmException e) {
+            }
+            if (publicKey == null) {
+                publicKey = new X509PublicKey(alg_oid, getEncoded(),
+                        subjectPublicKey);
+            }
+        }
+        return publicKey;
+    }
+    
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
+            AlgorithmIdentifier.ASN1, ASN1BitString.getInstance() }) {
+
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+            return new SubjectPublicKeyInfo(
+                    (AlgorithmIdentifier) values[0],
+                    ((BitString) values[1]).bytes,
+                    ((BitString) values[1]).unusedBits,
+                    in.getEncoded());
+        }
+
+        protected void getValues(Object object, Object[] values) {
+
+            SubjectPublicKeyInfo spki = (SubjectPublicKeyInfo) object;
+
+            values[0] = spki.algorithmID;
+            values[1] = new BitString(spki.subjectPublicKey, spki.unusedBits);
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/TBSCertList.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/TBSCertList.java
new file mode 100644
index 0000000..597ca59
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/TBSCertList.java
@@ -0,0 +1,442 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.asn1.ASN1Explicit;
+import org.apache.harmony.security.asn1.ASN1Integer;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1SequenceOf;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.x501.Name;
+
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with TBSCertList structure which is the part of X.509 CRL
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *
+ * <pre>
+ *   TBSCertList  ::=  SEQUENCE  {
+ *        version                 Version OPTIONAL,
+ *                                     -- if present, MUST be v2
+ *        signature               AlgorithmIdentifier,
+ *        issuer                  Name,
+ *        thisUpdate              Time,
+ *        nextUpdate              Time OPTIONAL,
+ *        revokedCertificates     SEQUENCE OF SEQUENCE  {
+ *             userCertificate         CertificateSerialNumber,
+ *             revocationDate          Time,
+ *             crlEntryExtensions      Extensions OPTIONAL
+ *                                           -- if present, MUST be v2
+ *                                  }  OPTIONAL,
+ *        crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
+ *                                           -- if present, MUST be v2
+ *   }
+ * </pre>
+ */
+public class TBSCertList {
+
+    // the value of version field of the structure
+    private final int version; 
+    // the value of signature field of the structure
+    private final AlgorithmIdentifier signature; 
+    // the value of issuer field of the structure
+    private final Name issuer;
+    // the value of thisUpdate of the structure
+    private final Date thisUpdate;
+    // the value of nextUpdate of the structure
+    private final Date nextUpdate;
+    // the value of revokedCertificates of the structure
+    private final List revokedCertificates;
+    // the value of crlExtensions field of the structure
+    private final Extensions crlExtensions;
+    // the ASN.1 encoded form of TBSCertList
+    private byte[] encoding;
+
+    public static class RevokedCertificate {
+        private final BigInteger userCertificate;
+        private final Date revocationDate;
+        private final Extensions crlEntryExtensions;
+        
+        private boolean issuerRetrieved;
+        private X500Principal issuer;
+        private byte[] encoding;
+
+        public RevokedCertificate(BigInteger userCertificate,
+                Date revocationDate, Extensions crlEntryExtensions) {
+            this.userCertificate = userCertificate;
+            this.revocationDate = revocationDate;
+            this.crlEntryExtensions = crlEntryExtensions;
+        }
+
+        public Extensions getCrlEntryExtensions() {
+            return crlEntryExtensions;
+        }
+
+        public BigInteger getUserCertificate() {
+            return userCertificate;
+        }
+
+        public Date getRevocationDate() {
+            return revocationDate;
+        }
+
+        /**
+         * Returns the value of Certificate Issuer Extension, if it is
+         * presented.
+         */
+        public X500Principal getIssuer() {
+            if (crlEntryExtensions == null) {
+                return null;
+            }
+            if (!issuerRetrieved) {
+                try {
+                    issuer =  
+                        crlEntryExtensions.valueOfCertificateIssuerExtension();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+                issuerRetrieved = true;
+            }
+            return issuer;
+        }
+        
+        public byte[] getEncoded() {
+            if (encoding == null) {
+                encoding = ASN1.encode(this);
+            }
+            return encoding;
+        }
+        
+        public boolean equals(Object rc) {
+            if (!(rc instanceof RevokedCertificate)) {
+                return false;
+            }
+            RevokedCertificate rcert = (RevokedCertificate) rc;
+            return userCertificate.equals(rcert.userCertificate)
+                && ((revocationDate.getTime() / 1000) 
+                        == (rcert.revocationDate.getTime() / 1000))
+                && ((crlEntryExtensions == null)
+                    ? rcert.crlEntryExtensions == null
+                    : crlEntryExtensions.equals(rcert.crlEntryExtensions));
+        }
+
+        /**
+         * Places the string representation of extension value
+         * into the StringBuffer object.
+         */
+        public void dumpValue(StringBuffer buffer, String prefix) {
+            buffer.append(prefix).append("Certificate Serial Number: ") //$NON-NLS-1$
+                .append(userCertificate).append('\n');
+            buffer.append(prefix).append("Revocation Date: ") //$NON-NLS-1$
+                .append(revocationDate);
+            if (crlEntryExtensions != null) {
+                buffer.append('\n').append(prefix)
+                    .append("CRL Entry Extensions: ["); //$NON-NLS-1$
+                crlEntryExtensions.dumpValue(buffer, prefix + "  "); //$NON-NLS-1$
+                buffer.append(prefix).append(']');
+            }
+        }
+        
+        public static ASN1Sequence ASN1 = new ASN1Sequence(
+                new ASN1Type[] {ASN1Integer.getInstance(), Time.ASN1,
+                Extensions.ASN1}) {
+            {
+                setOptional(2);
+            }
+
+            protected Object getDecodedObject(BerInputStream in) {
+                Object[] values = (Object[]) in.content;
+
+                return new RevokedCertificate(
+                            new BigInteger((byte[]) values[0]),
+                            (Date) values[1],
+                            (Extensions) values[2]
+                        );
+            }
+
+            protected void getValues(Object object, Object[] values) {
+                RevokedCertificate rcert = (RevokedCertificate) object;
+
+                values[0] = rcert.userCertificate.toByteArray();
+                values[1] = rcert.revocationDate;
+                values[2] = rcert.crlEntryExtensions;
+            }
+        };
+    }
+
+    /**
+     * Constructs the instance of TBSCertList without optional fields.
+     * Take a note, that regarding to the rfc 3280 (p. 49):
+     * "When CRLs are issued, the CRLs MUST be version 2 CRLs, include the date
+     * by which the next CRL will be issued in the nextUpdate field (section
+     * 5.1.2.5), include the CRL number extension (section 5.2.3), and include
+     * the authority key identifier extension (section 5.2.1). Conforming
+     * applications that support CRLs are REQUIRED to process both version 1 and
+     * version 2 complete CRLs that provide revocation information for all
+     * certificates issued by one CA. Conforming applications are NOT REQUIRED
+     * to support processing of delta CRLs, indirect CRLs, or CRLs with a scope
+     * other than all certificates issued by one CA."
+     * @param   signature:  AlgorithmIdentifier
+     * @param   issuer: Name
+     * @param   thisUpdate: Time
+     */
+    public TBSCertList(AlgorithmIdentifier signature, 
+            Name issuer, Date thisUpdate) {
+        this.version = 1; 
+        this.signature = signature; 
+        this.issuer = issuer;
+        this.thisUpdate = thisUpdate;
+        this.nextUpdate = null;
+        this.revokedCertificates = null;
+        this.crlExtensions = null;
+    }
+
+    /**
+     * Constructs the instance of TBSCertList with all optional fields
+     * @param   version: version of the CRL. Should be 1 or 2. 
+     * Note that if the version of CRL is 1, then nextUpdate,
+     * crlExtensions fields of CRL and crlEntryExtensions field
+     * of CRL entry must not be presented in CRL.
+     * FIXME: do check for it.
+     * @param   signature:  AlgorithmIdentifier
+     * @param   issuer: Name
+     * @param   thisUpdate: Time
+     * @param   nextUpdate: Time
+     * @param   revokedCertificates:    List
+     * @param   crlExtensions:  Extensions
+     */
+    public TBSCertList(int version, AlgorithmIdentifier signature, 
+            Name issuer, Date thisUpdate, Date nextUpdate, 
+            List revokedCertificates, Extensions crlExtensions) {
+        this.version = version; 
+        this.signature = signature; 
+        this.issuer = issuer;
+        this.thisUpdate = thisUpdate;
+        this.nextUpdate = nextUpdate;
+        this.revokedCertificates = revokedCertificates;
+        this.crlExtensions = crlExtensions;
+    }
+
+    // Constructs the object with associated ASN.1 encoding
+    private TBSCertList(int version, AlgorithmIdentifier signature, 
+            Name issuer, Date thisUpdate, Date nextUpdate, 
+            List revokedCertificates, Extensions crlExtensions,
+            byte[] encoding) {
+        this.version = version; 
+        this.signature = signature; 
+        this.issuer = issuer;
+        this.thisUpdate = thisUpdate;
+        this.nextUpdate = nextUpdate;
+        this.revokedCertificates = revokedCertificates;
+        this.crlExtensions = crlExtensions;
+        this.encoding = encoding;
+    }
+
+    /**
+     * Returns the value of version field of the structure.
+     * @return  version
+     */
+    public int getVersion() {
+        return version;
+    }
+
+    /**
+     * Returns the value of signature field of the structure.
+     * @return  signature
+     */
+    public AlgorithmIdentifier getSignature() {
+        return signature;
+    }
+    
+    /**
+     * Returns the value of issuer field of the structure.
+     * @return  issuer
+     */
+    public Name getIssuer() {
+        return issuer;
+    }
+    
+    /**
+     * Returns the value of thisUpdate field of the structure.
+     * @return thisUpdate
+     */
+    public Date getThisUpdate() {
+        return thisUpdate;
+    }
+    
+    /**
+     * Returns the value of nextUpdate field of the structure.
+     * @return nextUpdate
+     */
+    public Date getNextUpdate() {
+        return nextUpdate;
+    }
+    
+    /**
+     * Returns the value of revokedCertificates field of the structure.
+     * @return revokedCertificates
+     */
+    public List getRevokedCertificates() {
+        return revokedCertificates;
+    }
+
+    /**
+     * Returns the value of crlExtensions field of the structure.
+     * @return  extensions
+     */
+    public Extensions getCrlExtensions() {
+        return crlExtensions;
+    }
+
+    /**
+     * Returns ASN.1 encoded form of this X.509 TBSCertList value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+    
+    public boolean equals(Object tbs) {
+        if (!(tbs instanceof TBSCertList)) {
+            return false;
+        }
+        TBSCertList tbscert = (TBSCertList) tbs;
+        return (version == tbscert.version)
+            && (signature.equals(tbscert.signature))
+            // FIXME use Name.equals when it will be implemented
+            && (Arrays.equals(issuer.getEncoded(), tbscert.issuer.getEncoded()))
+            && ((thisUpdate.getTime() / 1000) 
+                    == (tbscert.thisUpdate.getTime() / 1000))
+            && ((nextUpdate == null) 
+                    ? tbscert.nextUpdate == null
+                    : ((nextUpdate.getTime() / 1000) 
+                        == (tbscert.nextUpdate.getTime() / 1000)))
+            && ((((revokedCertificates == null) 
+                            || (tbscert.revokedCertificates == null))
+                    && (revokedCertificates == tbscert.revokedCertificates))
+                || (revokedCertificates.containsAll(tbscert.revokedCertificates)
+                    && (revokedCertificates.size() 
+                        == tbscert.revokedCertificates.size())))
+            && ((crlExtensions == null)
+                    ? tbscert.crlExtensions == null
+                    : crlExtensions.equals(tbscert.crlExtensions));
+    }
+
+    /**
+     * Places the string representation of extension value
+     * into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer) {
+        buffer.append("X.509 CRL v").append(version); //$NON-NLS-1$
+        buffer.append("\nSignature Algorithm: ["); //$NON-NLS-1$
+        signature.dumpValue(buffer);
+        buffer.append(']');
+        buffer.append("\nIssuer: ").append(issuer.getName(X500Principal.RFC2253)); //$NON-NLS-1$
+        buffer.append("\n\nThis Update: ").append(thisUpdate); //$NON-NLS-1$
+        buffer.append("\nNext Update: ").append(nextUpdate).append('\n'); //$NON-NLS-1$
+        if (revokedCertificates != null) {
+            buffer.append("\nRevoked Certificates: ") //$NON-NLS-1$
+                .append(revokedCertificates.size()).append(" ["); //$NON-NLS-1$
+            int number = 1;
+            for (Iterator it = revokedCertificates.iterator();it.hasNext();) {
+                buffer.append("\n  [").append(number++).append(']'); //$NON-NLS-1$
+                ((RevokedCertificate) it.next()).dumpValue(buffer, "  "); //$NON-NLS-1$
+                buffer.append('\n');
+            }
+            buffer.append("]\n"); //$NON-NLS-1$
+        }
+        if (crlExtensions != null) {
+            buffer.append("\nCRL Extensions: ") //$NON-NLS-1$
+                .append(crlExtensions.size()).append(" ["); //$NON-NLS-1$
+            crlExtensions.dumpValue(buffer, "  "); //$NON-NLS-1$
+            buffer.append("]\n"); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * X.509 TBSCertList encoder/decoder.
+     */
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
+            ASN1Integer.getInstance(), // version
+            AlgorithmIdentifier.ASN1,  // signature
+            Name.ASN1, // issuer
+            Time.ASN1, // thisUpdate
+            Time.ASN1, // nextUpdate
+            new ASN1SequenceOf(RevokedCertificate.ASN1), // revokedCertificates
+            new ASN1Explicit(0, Extensions.ASN1) // crlExtensions
+                }) {
+        {
+            setOptional(0);
+            setOptional(4);
+            setOptional(5);
+            setOptional(6);
+        }
+
+        protected Object getDecodedObject(BerInputStream in) 
+                        throws IOException {
+            Object[] values = (Object[]) in.content;
+            return new TBSCertList(
+                        (values[0] == null) 
+                            ? 1
+                            : ASN1Integer.toIntValue(values[0])+1,
+                        (AlgorithmIdentifier) values[1],
+                        (Name) values[2], 
+                        (Date) values[3], 
+                        (Date) values[4], 
+                        (List) values[5],
+                        (Extensions) values[6],
+                        in.getEncoded()
+                    );
+        }
+
+        protected void getValues(Object object, Object[] values) {
+            TBSCertList tbs = (TBSCertList) object;
+            values[0] = (tbs.version > 1)
+                ? ASN1Integer.fromIntValue(tbs.version - 1) : null;
+            values[1] = tbs.signature;
+            values[2] = tbs.issuer; 
+            values[3] = tbs.thisUpdate;
+            values[4] = tbs.nextUpdate;
+            values[5] = tbs.revokedCertificates;
+            values[6] = tbs.crlExtensions;
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/TBSCertificate.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/TBSCertificate.java
new file mode 100644
index 0000000..aaafe3a
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/TBSCertificate.java
@@ -0,0 +1,353 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import java.math.BigInteger;
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.harmony.security.asn1.ASN1BitString;
+import org.apache.harmony.security.asn1.ASN1Explicit;
+import org.apache.harmony.security.asn1.ASN1Implicit;
+import org.apache.harmony.security.asn1.ASN1Integer;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.asn1.BitString;
+import org.apache.harmony.security.x501.Name;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with TBSCertificate structure which is the part of X.509 certificate
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *
+ * <pre>
+ *  TBSCertificate  ::=  SEQUENCE  {
+ *       version         [0]  EXPLICIT Version DEFAULT v1,
+ *       serialNumber         CertificateSerialNumber,
+ *       signature            AlgorithmIdentifier,
+ *       issuer               Name,
+ *       validity             Validity,
+ *       subject              Name,
+ *       subjectPublicKeyInfo SubjectPublicKeyInfo,
+ *       issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
+ *                            -- If present, version MUST be v2 or v3
+ *       subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
+ *                            -- If present, version MUST be v2 or v3
+ *       extensions      [3]  EXPLICIT Extensions OPTIONAL
+ *                            -- If present, version MUST be v3
+ *  }
+ * </pre>
+ */
+public class TBSCertificate {
+
+    // the value of version field of the structure
+    private final int version; 
+    // the value of serialNumber field of the structure
+    private final BigInteger serialNumber;
+    // the value of signature field of the structure
+    private final AlgorithmIdentifier signature; 
+    // the value of issuer field of the structure
+    private final Name issuer;
+    // the value of validity field of the structure
+    private final Validity validity;
+    // the value of subject field of the structure
+    private final Name subject;
+    // the value of subjectPublicKeyInfo field of the structure
+    private final SubjectPublicKeyInfo subjectPublicKeyInfo;
+    // the value of issuerUniqueID field of the structure
+    private final boolean[] issuerUniqueID;
+    // the value of subjectUniqueID field of the structure
+    private final boolean[] subjectUniqueID;
+    // the value of extensions field of the structure
+    private final Extensions extensions;
+    // the ASN.1 encoded form of TBSCertificate
+    byte[] encoding;
+
+    /**
+     * Constructs the instance of TBSCertificate without optional
+     * fields (issuerUniqueID, subjectUniqueID, extensions)
+     * @param   version :   int
+     * @param   serialNumber    :   BigInteger
+     * @param   signature   :   AlgorithmIdentifier
+     * @param   issuer  :   Name
+     * @param   validity    :   Validity
+     * @param   subject :   Name
+     * @param   subjectPublicKeyInfo    :   SubjectPublicKeyInfo
+     */
+    public TBSCertificate(int version, BigInteger serialNumber, 
+                          AlgorithmIdentifier signature, Name issuer,
+                          Validity validity, Name subject, 
+                          SubjectPublicKeyInfo subjectPublicKeyInfo) {
+        this(version, serialNumber, signature, issuer, validity, subject, 
+             subjectPublicKeyInfo, null, null, null);
+    }
+
+    /**
+     * TODO
+     * @param   version:    int
+     * @param   serialNumber:   BigInteger
+     * @param   signature:  AlgorithmIdentifier
+     * @param   issuer: Name
+     * @param   validity:   Validity
+     * @param   subject:    Name
+     * @param   subjectPublicKeyInfo:   SubjectPublicKeyInfo
+     * @param   issuerUniqueID: byte[]
+     * @param   subjectUniqueID:    byte[]
+     * @param   extensions: Extensions
+     */
+    public TBSCertificate(int version, BigInteger serialNumber, 
+                          AlgorithmIdentifier signature, Name issuer,
+                          Validity validity, Name subject, 
+                          SubjectPublicKeyInfo subjectPublicKeyInfo,
+                          boolean[] issuerUniqueID, boolean[] subjectUniqueID,
+                          Extensions extensions) {
+        this.version = version; 
+        this.serialNumber = serialNumber;
+        this.signature = signature; 
+        this.issuer = issuer;
+        this.validity = validity;
+        this.subject = subject;
+        this.subjectPublicKeyInfo = subjectPublicKeyInfo;
+        this.issuerUniqueID = issuerUniqueID;
+        this.subjectUniqueID = subjectUniqueID;
+        this.extensions = extensions;
+    }
+        
+    // 
+    // TODO
+    // @param   version:    int
+    // @param   serialNumber:   BigInteger
+    // @param   signature:  AlgorithmIdentifier
+    // @param   issuer: Name
+    // @param   validity:   Validity
+    // @param   subject:    Name
+    // @param   subjectPublicKeyInfo:   SubjectPublicKeyInfo
+    // @param   issuerUniqueID: byte[]
+    // @param   subjectUniqueID:    byte[]
+    // @param   extensions: Extensions
+    // @param   encoding:   byte[]
+    // 
+    private TBSCertificate(int version, BigInteger serialNumber, 
+                          AlgorithmIdentifier signature, Name issuer,
+                          Validity validity, Name subject, 
+                          SubjectPublicKeyInfo subjectPublicKeyInfo,
+                          boolean[] issuerUniqueID, boolean[] subjectUniqueID,
+                          Extensions extensions, byte[] encoding) {
+        this(version, serialNumber, signature, issuer, validity, subject, 
+             subjectPublicKeyInfo, issuerUniqueID, subjectUniqueID, extensions);
+        this.encoding = encoding;
+    }
+        
+    /**
+     * Returns the value of version field of the structure.
+     * @return  version
+     */
+    public int getVersion() {
+        return version;
+    }
+
+    /**
+     * Returns the value of serialNumber field of the structure.
+     * @return  serialNumber
+     */
+    public BigInteger getSerialNumber() {
+        return serialNumber;
+    }
+    
+    /**
+     * Returns the value of signature field of the structure.
+     * @return  signature
+     */
+    public AlgorithmIdentifier getSignature() {
+        return signature;
+    }
+    
+    /**
+     * Returns the value of issuer field of the structure.
+     * @return  issuer
+     */
+    public Name getIssuer() {
+        return issuer;
+    }
+    
+    /**
+     * Returns the value of validity field of the structure.
+     * @return  validity
+     */
+    public Validity getValidity() {
+        return validity;
+    }
+    
+    /**
+     * Returns the value of subject field of the structure.
+     * @return  subject
+     */
+    public Name getSubject() {
+        return subject;
+    }
+    
+    /**
+     * Returns the value of subjectPublicKeyInfo field of the structure.
+     * @return  subjectPublicKeyInfo
+     */
+    public SubjectPublicKeyInfo getSubjectPublicKeyInfo() {
+        return subjectPublicKeyInfo;
+    }
+    
+    /**
+     * Returns the value of issuerUniqueID field of the structure.
+     * @return  issuerUniqueID
+     */
+    public boolean[] getIssuerUniqueID() {
+        return issuerUniqueID;
+    }
+    
+    /**
+     * Returns the value of subjectUniqueID field of the structure.
+     * @return  subjectUniqueID
+     */
+    public boolean[] getSubjectUniqueID() {
+        return subjectUniqueID;
+    }
+    
+    /**
+     * Returns the value of extensions field of the structure.
+     * @return  extensions
+     */
+    public Extensions getExtensions() {
+        return extensions;
+    }
+
+    /**
+     * Returns ASN.1 encoded form of this X.509 TBSCertificate value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    /**
+     * Places the string representation into the StringBuffer object.
+     */
+    public void dumpValue(StringBuffer buffer) {
+        buffer.append('[');
+        buffer.append("\n  Version: V").append(version+1); //$NON-NLS-1$
+        buffer.append("\n  Subject: ") //$NON-NLS-1$
+            .append(subject.getName(X500Principal.RFC2253));
+        buffer.append("\n  Signature Algorithm: "); //$NON-NLS-1$
+        signature.dumpValue(buffer);
+        buffer.append("\n  Key: "); //$NON-NLS-1$
+        buffer.append(subjectPublicKeyInfo.getPublicKey().toString());
+        buffer.append("\n  Validity: [From: "); //$NON-NLS-1$
+        buffer.append(validity.getNotBefore());
+        buffer.append("\n               To: "); //$NON-NLS-1$
+        buffer.append(validity.getNotAfter()).append(']');
+        buffer.append("\n  Issuer: "); //$NON-NLS-1$
+        buffer.append(issuer.getName(X500Principal.RFC2253));
+        buffer.append("\n  Serial Number: "); //$NON-NLS-1$
+        buffer.append(serialNumber);
+        if (issuerUniqueID != null) {
+            buffer.append("\n  Issuer Id: "); //$NON-NLS-1$
+            for (int i=0; i<issuerUniqueID.length; i++) {
+                buffer.append(issuerUniqueID[i] ? '1' : '0');
+            }
+        }
+        if (subjectUniqueID != null) {
+            buffer.append("\n  Subject Id: "); //$NON-NLS-1$
+            for (int i=0; i<subjectUniqueID.length; i++) {
+                buffer.append(subjectUniqueID[i] ? '1' : '0');
+            }
+        }
+        if (extensions != null) {
+            buffer.append("\n\n  Extensions: "); //$NON-NLS-1$
+            buffer.append("[\n"); //$NON-NLS-1$
+            extensions.dumpValue(buffer, "    "); //$NON-NLS-1$
+            buffer.append("  ]"); //$NON-NLS-1$
+        }
+        buffer.append("\n]"); //$NON-NLS-1$
+    }
+
+    /**
+     * X.509 TBSCertificate encoder/decoder.
+     */
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
+            new ASN1Explicit(0, ASN1Integer.getInstance()), ASN1Integer.getInstance(), 
+            AlgorithmIdentifier.ASN1, Name.ASN1,
+            Validity.ASN1, Name.ASN1, SubjectPublicKeyInfo.ASN1, 
+            new ASN1Implicit(1, ASN1BitString.getInstance()), 
+            new ASN1Implicit(2, ASN1BitString.getInstance()), 
+            new ASN1Explicit(3, Extensions.ASN1)}) {
+        {
+            setDefault(new byte[] {0}, 0);
+            setOptional(7);
+            setOptional(8);
+            setOptional(9);
+        }
+
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+
+            boolean[] issuerUniqueID = (values[7] == null) 
+                ? null : ((BitString) values[7]).toBooleanArray();
+            boolean[] subjectUniqueID = (values[8] == null) 
+                ? null : ((BitString) values[8]).toBooleanArray();
+            return new TBSCertificate(
+                        ASN1Integer.toIntValue(values[0]),
+                        new BigInteger((byte[]) values[1]), 
+                        (AlgorithmIdentifier) values[2],
+                        (Name) values[3], 
+                        (Validity) values[4], 
+                        (Name) values[5],
+                        (SubjectPublicKeyInfo) values[6], 
+                        issuerUniqueID,
+                        subjectUniqueID,
+                        (Extensions) values[9],
+                        in.getEncoded()
+                    );
+        }
+
+        protected void getValues(Object object, Object[] values) {
+            TBSCertificate tbs = (TBSCertificate) object;
+            values[0] = ASN1Integer.fromIntValue(tbs.version);
+            values[1] = tbs.serialNumber.toByteArray();
+            values[2] = tbs.signature;
+            values[3] = tbs.issuer; 
+            values[4] = tbs.validity;
+            values[5] = tbs.subject;
+            values[6] = tbs.subjectPublicKeyInfo;
+            if (tbs.issuerUniqueID != null) {
+                values[7] = new BitString(tbs.issuerUniqueID);
+            }
+            if (tbs.subjectUniqueID != null) {
+                values[8] = new BitString(tbs.subjectUniqueID);
+            }
+            values[9] = tbs.extensions;
+        }
+    };
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/Time.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/Time.java
new file mode 100644
index 0000000..912e014
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/Time.java
@@ -0,0 +1,65 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import org.apache.harmony.security.asn1.ASN1Choice;
+import org.apache.harmony.security.asn1.ASN1GeneralizedTime;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.ASN1UTCTime;
+
+/**
+ * Class represents the work with the following X.509 structure:
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *
+ * <pre>
+ * Time ::= CHOICE {
+ *       utcTime        UTCTime,
+ *       generalTime    GeneralizedTime 
+ * }
+ * </pre>
+ */
+public class Time {
+    
+    private static final long JAN_01_2050 = 2524608000000L;
+    
+    public static final ASN1Choice ASN1 = new ASN1Choice(new ASN1Type[] {
+            ASN1GeneralizedTime.getInstance(), ASN1UTCTime.getInstance() }) {
+
+        public int getIndex(java.lang.Object object) {
+            // choose encoding method (see RFC 3280 p. 22)
+            if (((java.util.Date) object).getTime() < JAN_01_2050) {
+                return 1; // it is before 2050, so encode as UTCTime
+            } else {
+                return 0; // it is after 2050, encode as GeneralizedTime
+            }
+        }
+
+        public Object getObjectToEncode(Object object) {
+            return object;
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/Utils.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/Utils.java
new file mode 100644
index 0000000..8c72710
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/Utils.java
@@ -0,0 +1,51 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Esin
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+/**
+ * Text utils for processing DN string representations
+ */
+
+public class Utils {
+    
+    /**
+     * Checks if the string is PrintableString (see X.680)
+     * @param str input string
+     * @return true if the string is PrintableString, false otherwise
+     */
+    public static boolean isPrintableString(String str) {
+        for (int i= 0; i< str.length(); ++i) {
+            char ch= str.charAt(i); 
+            if (!(ch== 0x20 
+                || ch>= 0x27 && ch<= 0x29 // '()
+                || ch>= 0x2B && ch<= 0x3A // +,-./0-9:
+                || ch== '=' 
+                || ch== '?'
+                || ch>= 'A' && ch<= 'Z'
+                || ch>= 'a' && ch<= 'z')) {
+                return false;
+            }
+        }
+        return true;
+    }
+}    
\ No newline at end of file
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/Validity.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/Validity.java
new file mode 100644
index 0000000..e5d9c19
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/Validity.java
@@ -0,0 +1,110 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander Y. Kleymenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.x509;
+
+import java.util.Date;
+
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+
+/**
+ * The class encapsulates the ASN.1 DER encoding/decoding work 
+ * with Validity structure which is the part of X.509 certificate
+ * (as specified in RFC 3280 -
+ *  Internet X.509 Public Key Infrastructure.
+ *  Certificate and Certificate Revocation List (CRL) Profile.
+ *  http://www.ietf.org/rfc/rfc3280.txt):
+ *
+ * <pre>
+ *  Validity ::= SEQUENCE {
+ *       notBefore      Time,
+ *       notAfter       Time 
+ *  }
+ * </pre>
+ */
+public class Validity {
+    // the value of notBefore field of the structure
+    private final Date notBefore;
+    // the value of notAfter field of the structure
+    private final Date notAfter;
+    // the ASN.1 encoded form of Validity
+    private byte[] encoding;
+
+    /**
+     * TODO
+     * @param   notBefore:  Date
+     * @param   notAfter:   Date
+     */
+    public Validity(Date notBefore, Date notAfter) {
+        this.notBefore = notBefore;
+        this.notAfter = notAfter;
+    }
+
+    /**
+     * Returns the value of notBefore field of the structure.
+     * @return  notBefore
+     */
+    public Date getNotBefore() {
+        return notBefore;
+    }
+
+    /**
+     * Returns the value of notAfter field of the structure.
+     * @return  notAfter
+     */
+    public Date getNotAfter() {
+        return notAfter;
+    }
+    
+    /**
+     * Returns ASN.1 encoded form of this X.509 Validity value.
+     * @return a byte array containing ASN.1 encode form.
+     */
+    public byte[] getEncoded() {
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    /**
+     * ASN.1 DER X.509 Validity encoder/decoder class.
+     */
+    public static final ASN1Sequence ASN1 
+        = new ASN1Sequence(new ASN1Type[] {Time.ASN1, Time.ASN1 }) {
+
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+            return new Validity((Date) values[0], (Date) values[1]);
+        }
+
+        protected void getValues(Object object, Object[] values) {
+
+            Validity validity = (Validity) object;
+
+            values[0] = validity.notBefore;
+            values[1] = validity.notAfter;
+        }
+    };
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/X509PublicKey.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/X509PublicKey.java
new file mode 100644
index 0000000..cae6b97
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/X509PublicKey.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.security.x509;
+
+import java.security.PublicKey;
+
+public class X509PublicKey implements PublicKey {
+
+    private final String algorithm;
+
+    private final byte[] encoded;
+
+    private final byte[] keyBytes;
+
+    public X509PublicKey(String algorithm, byte[] encoded, byte[] keyBytes) {
+        this.algorithm = algorithm;
+        this.encoded = encoded;
+        this.keyBytes = keyBytes;
+    }
+
+    public String getAlgorithm() {
+        return algorithm;
+    }
+
+    public String getFormat() {
+        return "X.509"; // $NON-NLS-1$
+    }
+
+    public byte[] getEncoded() {
+        return encoded;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder("algorithm = "); // $NON-NLS-1$
+        buf.append(algorithm);
+        buf.append(", params unparsed, unparsed keybits = \n"); // $NON-NLS-1$
+        // TODO: implement compatible toString method() 
+        // buf.append(Arrays.toString(keyBytes));
+
+        return buf.toString();
+    }
+}
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/tsp/MessageImprint.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/tsp/MessageImprint.java
new file mode 100644
index 0000000..cf17ce1
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/tsp/MessageImprint.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+
+package org.apache.harmony.security.x509.tsp;
+
+import org.apache.harmony.security.asn1.ASN1OctetString;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.x509.AlgorithmIdentifier;
+
+/**
+ * As defined in Time-Stamp Protocol (TSP)
+ * (http://www.ietf.org/rfc/rfc3161.txt)
+ * 
+ * MessageImprint ::= SEQUENCE  {
+ *      hashAlgorithm                AlgorithmIdentifier,
+ *      hashedMessage                OCTET STRING  
+ * }
+ * 
+ */
+public class MessageImprint {
+    private final AlgorithmIdentifier algId;
+    private final byte [] hashedMessage;
+    
+    public MessageImprint(AlgorithmIdentifier algId, byte [] hashedMessage){
+        this.algId = algId;
+        this.hashedMessage = hashedMessage;
+    }
+    
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
+        AlgorithmIdentifier.ASN1,
+        ASN1OctetString.getInstance()}) {
+        
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+            return new MessageImprint(
+                    (AlgorithmIdentifier)values[0],
+                    (byte[])values[1]);
+        }
+        
+        protected void getValues(Object object, Object[] values) {
+            MessageImprint mi = (MessageImprint) object;
+            values[0] = mi.algId;
+            values[1] = mi.hashedMessage;
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/tsp/PKIFailureInfo.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/tsp/PKIFailureInfo.java
new file mode 100644
index 0000000..702513c
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/tsp/PKIFailureInfo.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+
+package org.apache.harmony.security.x509.tsp;
+
+import java.security.InvalidParameterException;
+
+/**
+   Corresponds to PKIFailureInfo structure.
+   See RFC 3161 -
+   Internet X.509 Public Key Infrastructure
+   Time-Stamp Protocol (TSP)
+   http://www.ietf.org/rfc/rfc3161.txt)
+    
+   PKIFailureInfo ::= BIT STRING {
+   badAlg               (0),
+     -- unrecognized or unsupported Algorithm Identifier
+   badRequest           (2),
+     -- transaction not permitted or supported
+   badDataFormat        (5),
+     -- the data submitted has the wrong format
+   timeNotAvailable    (14),
+     -- the TSA's time source is not available
+   unacceptedPolicy    (15),
+     -- the requested TSA policy is not supported by the TSA
+   unacceptedExtension (16),
+     -- the requested extension is not supported by the TSA
+    addInfoNotAvailable (17)
+      -- the additional information requested could not be understood
+      -- or is not available
+    systemFailure       (25)
+      -- the request cannot be handled due to system failure  }
+
+    The value of PKIFailureInfo can take only one of the values,
+    so it is represented by an integer here.
+ */
+public enum PKIFailureInfo {
+    /**
+     *  Unrecognized algorithm ID 
+     */
+    BAD_ALG(0),
+    
+    /**
+     *  Transaction is not supported 
+     */
+    BAD_REQUEST(2),
+    
+    /**
+     *  Data format is wrong 
+     */
+    BAD_DATA_FORMAT(5),
+    
+    /**
+     *  TSA cannot use the time source  
+     */
+    TIME_NOT_AVAILABLE(14),
+    
+    /**
+     *  The policy is not supported
+     */
+    UNACCEPTED_POLICY(15),
+    
+    /**
+     *  The extension is not supported
+     */
+    UNACCEPTED_EXTENSION(16),
+    
+    /**
+     *  The requested additional info is not available
+     */
+    ADD_INFO_NOT_AVAILABLE(17),
+    
+    /**
+     *  System failure has occured
+     */
+    SYSTEM_FAILURE(25);
+
+    
+    private final int value;
+
+    private static int maxValue;
+
+    PKIFailureInfo(int value) {
+        this.value = value;
+    }
+    
+    /**
+     * @return int value of the failure
+     */
+    public int getValue() {
+        return value;
+    }
+
+    /**
+     * @return maximum of values in the enum
+     */
+    public static int getMaxValue() {
+        if (maxValue == 0) {
+            for (PKIFailureInfo cur : values())
+                if (cur.value > maxValue) {
+                    maxValue = cur.value;
+                }
+        }
+        return maxValue;
+    }
+    
+    /**
+     * @param value
+     * @return
+     */
+    public static PKIFailureInfo getInstance(int value) {
+        for (PKIFailureInfo info : values()){
+            if (value == info.value) {
+                return info;
+            }
+        }
+        throw new InvalidParameterException("Unknown PKIFailureInfo value");
+    }
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/tsp/PKIStatus.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/tsp/PKIStatus.java
new file mode 100644
index 0000000..afe58b1
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/tsp/PKIStatus.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+
+package org.apache.harmony.security.x509.tsp;
+
+import java.security.InvalidParameterException;
+
+/**
+   Corresponds to PKIStatus structure.
+   See RFC 3161 -
+   Internet X.509 Public Key Infrastructure
+   Time-Stamp Protocol (TSP)
+   http://www.ietf.org/rfc/rfc3161.txt)
+    
+   PKIStatus ::= INTEGER {
+      granted                (0),
+      -- when the PKIStatus contains the value zero a TimeStampToken, as
+         requested, is present.
+      grantedWithMods        (1),
+       -- when the PKIStatus contains the value one a TimeStampToken,
+         with modifications, is present.
+      rejection              (2),
+      waiting                (3),
+      revocationWarning      (4),
+       -- this message contains a warning that a revocation is
+       -- imminent
+      revocationNotification (5)
+       -- notification that a revocation has occurred  }
+ */
+public enum PKIStatus {
+    /** 
+     * TimeStampToken is present as requested
+     */
+    GRANTED(0),
+    /** 
+     * TimeStampToken is present with modifications
+     */
+    GRANTED_WITH_MODS(1),
+    /**
+     * rejected
+     */
+    REJECTION(2),
+    /**
+     * waiting
+     */
+    WAITING(3),
+    /** 
+     * revocation time comes soon
+     */
+    REVOCATION_WARNING(4),
+    /**
+     * revoked
+     */
+    REVOCATION_NOTIFICATION(5);
+
+    private final int status;
+    PKIStatus(int status) {
+        this.status = status;
+    }
+    
+    /**
+     * @return int value of the status
+     */
+    public int getStatus(){
+        return status;
+    }
+    
+    public static PKIStatus getInstance(int status) {
+        for (PKIStatus curStatus : values()) {
+            if (status == curStatus.status) {
+                return curStatus;
+            }
+        }
+        throw new InvalidParameterException("Unknown PKIStatus value");
+    }
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/tsp/PKIStatusInfo.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/tsp/PKIStatusInfo.java
new file mode 100644
index 0000000..336a60d
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/tsp/PKIStatusInfo.java
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+
+package org.apache.harmony.security.x509.tsp;
+
+import java.math.BigInteger;
+import java.util.List;
+
+import org.apache.harmony.security.asn1.ASN1BitString;
+import org.apache.harmony.security.asn1.ASN1Integer;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1SequenceOf;
+import org.apache.harmony.security.asn1.ASN1StringType;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.asn1.BitString;
+
+
+/**
+ * As defined in Time-Stamp Protocol (TSP)
+ * (http://www.ietf.org/rfc/rfc3161.txt)
+ * 
+ * PKIStatusInfo ::= SEQUENCE { 
+ *    status PKIStatus, 
+ *    statusString PKIFreeText OPTIONAL, 
+ *    failInfo PKIFailureInfo OPTIONAL
+ * }
+ * 
+ */
+public class PKIStatusInfo {
+
+    private final PKIStatus status;
+    
+    private final List statusString;
+    
+    private final PKIFailureInfo failInfo;
+    
+    public PKIStatusInfo(PKIStatus pKIStatus, List statusString,
+            PKIFailureInfo failInfo) {
+        this.status = pKIStatus;
+        this.statusString = statusString;
+        this.failInfo = failInfo;
+    }
+    
+    public String toString(){
+        StringBuffer res = new StringBuffer();
+        res.append("-- PKIStatusInfo:");
+        res.append("\nPKIStatus : ");
+        res.append(status);
+        res.append("\nstatusString:  ");
+        res.append(statusString);
+        res.append("\nfailInfo:  ");
+        res.append(failInfo);
+        res.append("\n-- PKIStatusInfo End\n");
+        return res.toString();
+    }
+    
+    /**
+     * @return Returns the failInfo.
+     */
+    public PKIFailureInfo getFailInfo() {
+        return failInfo;
+    }
+
+    /**
+     * @return Returns the pKIStatus.
+     */
+    public PKIStatus getStatus() {
+        return status;
+    }
+
+    /**
+     * @return Returns the statusString.
+     */
+    public List getStatusString() {
+        return statusString;
+    }
+    
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
+        ASN1Integer.getInstance(),                      // status
+        new ASN1SequenceOf(ASN1StringType.UTF8STRING),  // statusString
+        ASN1BitString.getInstance() }) {                // failInfo
+        {
+            setOptional(1);
+            setOptional(2);
+        }
+        
+        protected void getValues(Object object, Object[] values) {
+            PKIStatusInfo psi = (PKIStatusInfo) object;
+            values[0] = BigInteger.valueOf(psi.status.getStatus())
+                    .toByteArray();
+            values[1] = psi.statusString;
+            if (psi.failInfo != null) {
+                // set the needed bit in the bit string
+                boolean[] failInfoBoolArray = new boolean[PKIFailureInfo
+                        .getMaxValue()];
+                failInfoBoolArray[psi.failInfo.getValue()] = true;
+                values[2] = new BitString(failInfoBoolArray);
+            } else {
+                values[2] = null;
+            }
+        }
+        
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+            
+            int failInfoValue = -1;
+            if (values[2] != null) {
+                boolean[] failInfoBoolArray = (values[2] == null) ? null
+                        : ((BitString) values[2]).toBooleanArray();
+                for (int i = 0; i < failInfoBoolArray.length; i++) {
+                    if (failInfoBoolArray[i]) {
+                        failInfoValue = i;
+                        break;
+                    }
+                }
+            }
+            return new PKIStatusInfo(
+                    PKIStatus.getInstance(ASN1Integer.toIntValue(values[0])),
+                    (List)values[1],
+                    PKIFailureInfo.getInstance(failInfoValue));
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/tsp/TSTInfo.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/tsp/TSTInfo.java
new file mode 100644
index 0000000..4c9454e
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/tsp/TSTInfo.java
@@ -0,0 +1,306 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+
+package org.apache.harmony.security.x509.tsp;
+
+import java.math.BigInteger;
+import java.util.Date;
+
+import org.apache.harmony.security.asn1.ASN1Boolean;
+import org.apache.harmony.security.asn1.ASN1Explicit;
+import org.apache.harmony.security.asn1.ASN1GeneralizedTime;
+import org.apache.harmony.security.asn1.ASN1Implicit;
+import org.apache.harmony.security.asn1.ASN1Integer;
+import org.apache.harmony.security.asn1.ASN1Oid;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.asn1.ObjectIdentifier;
+import org.apache.harmony.security.internal.nls.Messages;
+import org.apache.harmony.security.x509.Extensions;
+import org.apache.harmony.security.x509.GeneralName;
+
+/**
+ * As defined in Time-Stamp Protocol (TSP) 
+ * (http://www.ietf.org/rfc/rfc3161.txt)
+ * 
+ * TSTInfo ::= SEQUENCE  {
+ *    version                      INTEGER  { v1(1) },
+ *    policy                       TSAPolicyId,
+ *    messageImprint               MessageImprint,
+ *      -- MUST have the same value as the similar field in
+ *      -- TimeStampReq
+ *    serialNumber                 INTEGER,
+ *     -- Time-Stamping users MUST be ready to accommodate integers
+ *     -- up to 160 bits.
+ *    genTime                      GeneralizedTime,
+ *    accuracy                     Accuracy                 OPTIONAL,
+ *    ordering                     BOOLEAN             DEFAULT FALSE,
+ *    nonce                        INTEGER                  OPTIONAL,
+ *      -- MUST be present if the similar field was present
+ *      -- in TimeStampReq.  In that case it MUST have the same value.
+ *    tsa                          [0] GeneralName          OPTIONAL,
+ *    extensions                   [1] IMPLICIT Extensions   OPTIONAL
+ * }
+ *  
+ * TSAPolicyId ::= OBJECT IDENTIFIER
+ * 
+ * "tsa [0] GeneralName OPTIONAL" is EXPLICIT and the word EXPLICIT is omitted. 
+ */
+public class TSTInfo {
+    
+    private final int version;
+    
+    private final String policy;
+    
+    private final MessageImprint messageImprint;
+    
+    private final BigInteger serialNumber;
+    
+    private final Date genTime;
+    
+    private final int [] accuracy;
+    
+    private final Boolean ordering;
+    
+    private final BigInteger nonce;
+    
+    private final GeneralName tsa;
+    
+    private final Extensions extensions;
+    
+    public TSTInfo(int version, String policy, MessageImprint messageImprint,
+            BigInteger serialNumber, Date genTime, int[] accuracy,
+            Boolean ordering, BigInteger nonce, GeneralName tsa,
+            Extensions extensions) {
+        this.version = version;
+        this.policy = policy;
+        this.messageImprint = messageImprint;
+        this.serialNumber = serialNumber;
+        this.genTime = genTime;
+        this.accuracy = accuracy;
+        this.ordering = ordering;
+        this.nonce = nonce;
+        this.tsa = tsa;
+        this.extensions = extensions;
+    }
+    
+    public String toString() {
+        StringBuffer res = new StringBuffer();
+        res.append("-- TSTInfo:");
+        res.append("\nversion:  ");
+        res.append(version);
+        res.append("\npolicy:  ");
+        res.append(policy);
+        res.append("\nmessageImprint:  ");
+        res.append(messageImprint);
+        res.append("\nserialNumber:  ");
+        res.append(serialNumber);
+        res.append("\ngenTime:  ");
+        res.append(genTime);
+        res.append("\naccuracy:  ");
+        if (accuracy != null) {
+            res.append(accuracy[0] + " sec, " + accuracy[1] + " millis, "
+                    + accuracy[2] + " micros");
+        }
+        res.append("\nordering:  ");
+        res.append(ordering);
+        res.append("\nnonce:  ");
+        res.append(nonce);
+        res.append("\ntsa:  ");
+        res.append(tsa);
+        res.append("\nextensions:  ");
+        res.append(extensions);
+        res.append("\n-- TSTInfo End\n");
+        return res.toString();
+    }
+
+    /**
+     * @return Returns the accuracy.
+     */
+    public int[] getAccuracy() {
+        return accuracy;
+    }
+
+    /**
+     * @return Returns the extensions.
+     */
+    public Extensions getExtensions() {
+        return extensions;
+    }
+
+    /**
+     * @return Returns the genTime.
+     */
+    public Date getGenTime() {
+        return genTime;
+    }
+
+    /**
+     * @return Returns the messageImprint.
+     */
+    public MessageImprint getMessageImprint() {
+        return messageImprint;
+    }
+
+    /**
+     * @return Returns the nonce.
+     */
+    public BigInteger getNonce() {
+        return nonce;
+    }
+
+    /**
+     * @return Returns the ordering.
+     */
+    public Boolean getOrdering() {
+        return ordering;
+    }
+
+    /**
+     * @return Returns the policy.
+     */
+    public String getPolicy() {
+        return policy;
+    }
+
+    /**
+     * @return Returns the serialNumber.
+     */
+    public BigInteger getSerialNumber() {
+        return serialNumber;
+    }
+
+    /**
+     * @return Returns the tsa.
+     */
+    public GeneralName getTsa() {
+        return tsa;
+    }
+
+    /**
+     * @return Returns the version.
+     */
+    public int getVersion() {
+        return version;
+    }
+
+    /**
+         Accuracy ::= SEQUENCE {
+                seconds        INTEGER           OPTIONAL,
+                millis     [0] INTEGER  (1..999) OPTIONAL,
+                micros     [1] INTEGER  (1..999) OPTIONAL  }
+     */
+    public static final ASN1Sequence ACCURACY
+            = new ASN1Sequence(new ASN1Type[] {
+                    ASN1Integer.getInstance(),
+                    ASN1Integer.getInstance(),
+                    ASN1Integer.getInstance()
+            }) {
+        {
+            setOptional(0);
+            setOptional(1);
+            setOptional(2);
+        }
+        
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+            
+            int [] accuracy = new int [3];
+            for (int i = 0; i < 3; i++) {
+                if (values[i] != null) {
+                    accuracy[i] = ASN1Integer.toIntValue(values[i]);
+                    if (i > 0 && (accuracy[i] < 0 || accuracy[i] > 999)) {
+                        throw new RuntimeException(
+                        // Msg: "Time-stamp accuracy value is incorrect: {}"
+                                Messages.getString("security.1A3", accuracy[i]));
+                    }
+                }
+            }
+            return accuracy;
+        }
+        
+        protected void getValues(Object object, Object[] values) {
+            int [] accuracy = (int []) object;
+            for (int i = 0; i < 3; i++) {
+                if (i > 0 && (accuracy[i] < 0 || accuracy[i] > 999)) {
+                    throw new RuntimeException(
+                    // Msg: "Time-stamp accuracy value is incorrect: {0}"
+                            Messages.getString("security.1A3", accuracy[i]));
+                }
+                values[i] = BigInteger.valueOf(accuracy[i]).toByteArray();
+            }
+        }
+    };
+    
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] { 
+            ASN1Integer.getInstance(),              // version
+            ASN1Oid.getInstance(),                  // policy
+            MessageImprint.ASN1,                    // messageImprint
+            ASN1Integer.getInstance(),              // serialNumber
+            ASN1GeneralizedTime.getInstance(),      // genTime
+            ACCURACY,                               // accuracy
+            ASN1Boolean.getInstance(),              // ordering  
+            ASN1Integer.getInstance(),              // nonce
+            new ASN1Explicit(0, GeneralName.ASN1),  // tsa
+            new ASN1Implicit(1, Extensions.ASN1) }) {// extensions
+        {
+            setOptional(5);
+            setDefault(Boolean.FALSE, 6);
+            setOptional(7);
+            setOptional(8);
+            setOptional(9);
+        }
+
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+            
+            BigInteger nonce = (values[7] == null) ? null : new BigInteger(
+                    (byte[]) values[7]);
+            
+            return new TSTInfo(
+                    ASN1Integer.toIntValue(values[0]),
+                    ObjectIdentifier.toString((int[]) values[1]),
+                    (MessageImprint) values[2],
+                    new BigInteger((byte[]) values[3]),
+                    (Date) values[4],
+                    (int []) values[5],
+                    (Boolean) values[6],
+                    nonce,
+                    (GeneralName) values[8],
+                    (Extensions) values[9]);
+        }
+
+        protected void getValues(Object object, Object[] values) {
+            TSTInfo info = (TSTInfo) object;
+            
+            values[0] = ASN1Integer.fromIntValue(info.version);
+            values[1] = ObjectIdentifier.toIntArray(info.policy);
+            values[2] = info.messageImprint;
+            values[3] = info.serialNumber.toByteArray();
+            values[4] = info.genTime;
+            values[5] = info.accuracy;
+            values[6] = info.ordering;
+            values[7] = (info.nonce == null) ? null : info.nonce.toByteArray();
+            values[8] = info.tsa;
+            values[9] = info.extensions;
+        }
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/tsp/TimeStampReq.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/tsp/TimeStampReq.java
new file mode 100644
index 0000000..117ae27
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/tsp/TimeStampReq.java
@@ -0,0 +1,215 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+
+package org.apache.harmony.security.x509.tsp;
+
+import java.math.BigInteger;
+
+import org.apache.harmony.security.asn1.ASN1Boolean;
+import org.apache.harmony.security.asn1.ASN1Implicit;
+import org.apache.harmony.security.asn1.ASN1Integer;
+import org.apache.harmony.security.asn1.ASN1Oid;
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.asn1.ObjectIdentifier;
+import org.apache.harmony.security.x509.Extensions;
+
+/**
+ * As defined in Time-Stamp Protocol (TSP)
+ * (http://www.ietf.org/rfc/rfc3161.txt)
+ * 
+ * TimeStampReq ::= SEQUENCE  {
+ *    version                      INTEGER  { v1(1) },
+ *    messageImprint               MessageImprint,
+ *      --a hash algorithm OID and the hash value of the data to be
+ *      --time-stamped
+ *    reqPolicy             TSAPolicyId              OPTIONAL,
+ *    nonce                 INTEGER                  OPTIONAL,
+ *    certReq               BOOLEAN                  DEFAULT FALSE,
+ *    extensions            [0] IMPLICIT Extensions  OPTIONAL  
+ *  }
+ *  
+ *  TSAPolicyId ::= OBJECT IDENTIFIER
+ */
+public class TimeStampReq {
+    private final int version;
+
+    private final MessageImprint messageImprint;
+
+    private final String reqPolicy;
+
+    private final BigInteger nonce;
+
+    private final Boolean certReq;
+
+    private final Extensions extensions;
+    
+    private byte [] encoding;
+
+    public TimeStampReq(int version, MessageImprint messageImprint,
+            String reqPolicy, BigInteger nonce, Boolean certReq,
+            Extensions extensions) {
+        this.version = version;
+        this.messageImprint = messageImprint;
+        this.reqPolicy = reqPolicy;
+        this.nonce = nonce;
+        this.certReq = certReq;
+        this.extensions = extensions;
+    }
+
+    private TimeStampReq(int version, MessageImprint messageImprint,
+            String reqPolicy, BigInteger nonce, Boolean certReq,
+            Extensions extensions, byte [] encoding) {
+        this (version, messageImprint, reqPolicy, nonce, certReq, extensions);
+        this.encoding = encoding;
+    }
+
+    public String toString() {
+        StringBuffer res = new StringBuffer();
+        res.append("-- TimeStampReq:");
+        res.append("\nversion : ");
+        res.append(version);
+        res.append("\nmessageImprint:  ");
+        res.append(messageImprint);
+        res.append("\nreqPolicy:  ");
+        res.append(reqPolicy);
+        res.append("\nnonce:  ");
+        res.append(nonce);
+        res.append("\ncertReq:  ");
+        res.append(certReq);
+        res.append("\nextensions:  ");
+        res.append(extensions);
+        res.append("\n-- TimeStampReq End\n");
+        return res.toString();
+    }
+
+    /**
+     * Returns ASN.1 encoded form of this TimeStampReq.
+     * @return a byte array containing ASN.1 encoded form.
+     */
+    public byte [] getEncoded(){
+        if (encoding == null) {
+            encoding = ASN1.encode(this);
+        }
+        return encoding;
+    }
+
+    /**
+     * @return Returns the certReq.
+     */
+    public Boolean getCertReq() {
+        return certReq;
+    }
+
+    /**
+     * @return Returns the extensions.
+     */
+    public Extensions getExtensions() {
+        return extensions;
+    }
+
+    /**
+     * @return Returns the messageImprint.
+     */
+    public MessageImprint getMessageImprint() {
+        return messageImprint;
+    }
+
+    /**
+     * @return Returns the nonce.
+     */
+    public BigInteger getNonce() {
+        return nonce;
+    }
+
+    /**
+     * @return Returns the reqPolicy.
+     */
+    public String getReqPolicy() {
+        return reqPolicy;
+    }
+
+    /**
+     * @return Returns the version.
+     */
+    public int getVersion() {
+        return version;
+    }    
+    
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
+            ASN1Integer.getInstance(),              // version
+            MessageImprint.ASN1,                    // messageImprint 
+            ASN1Oid.getInstance(),                  // reqPolicy
+            ASN1Integer.getInstance(),              // nonce
+            ASN1Boolean.getInstance(),              // certReq
+            new ASN1Implicit(0, Extensions.ASN1)}) {// extensions
+                
+        {
+            setDefault(Boolean.FALSE, 4);
+            setOptional(2);
+            setOptional(3);
+            setOptional(5);
+        }
+        
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+            
+            String objID = (values[2] == null) ? null : ObjectIdentifier
+                    .toString((int[]) values[2]);
+            BigInteger nonce = (values[3] == null) ? null : new BigInteger(
+                    (byte[]) values[3]);
+            
+            if (values[5] == null) {
+                return new TimeStampReq(
+                        ASN1Integer.toIntValue(values[0]),
+                        (MessageImprint) values[1],
+                        objID,
+                        nonce,
+                        (Boolean) values[4],
+                        null,
+                        in.getEncoded()
+                   );
+            } else {
+                return new TimeStampReq(
+                        ASN1Integer.toIntValue(values[0]),
+                        (MessageImprint) values[1],
+                        objID,
+                        nonce,
+                        (Boolean) values[4],
+                        (Extensions) values[5],
+                        in.getEncoded()
+                   );
+            }
+        }
+        
+        protected void getValues(Object object, Object[] values) {
+            TimeStampReq req = (TimeStampReq) object;
+            values[0] = ASN1Integer.fromIntValue(req.version);
+            values[1] = req.messageImprint;
+            values[2] = (req.reqPolicy == null) ? null : ObjectIdentifier
+                    .toIntArray(req.reqPolicy);
+            values[3] = (req.nonce == null) ? null : req.nonce.toByteArray();
+            values[4] = (req.certReq == null) ? Boolean.FALSE : req.certReq;
+            values[5] = req.extensions;
+        }
+    };
+
+}
+
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/tsp/TimeStampResp.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/tsp/TimeStampResp.java
new file mode 100644
index 0000000..ea50a2d
--- /dev/null
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/tsp/TimeStampResp.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+
+package org.apache.harmony.security.x509.tsp;
+
+import org.apache.harmony.security.asn1.ASN1Sequence;
+import org.apache.harmony.security.asn1.ASN1Type;
+import org.apache.harmony.security.asn1.BerInputStream;
+import org.apache.harmony.security.pkcs7.ContentInfo;
+
+/**
+ * As defined in Time-Stamp Protocol (TSP)
+ * (http://www.ietf.org/rfc/rfc3161.txt)
+ * 
+ * TimeStampResp ::= SEQUENCE { 
+ *    status PKIStatusInfo, 
+ *    timeStampToken TimeStampToken OPTIONAL 
+ * }
+ * 
+ */
+public class TimeStampResp {
+
+    private final PKIStatusInfo status;
+
+    private final ContentInfo timeStampToken;
+    
+    public TimeStampResp(PKIStatusInfo status, ContentInfo timeStampToken) {
+        this.status = status;
+        this.timeStampToken = timeStampToken;
+    }
+    
+    public String toString(){
+        StringBuffer res = new StringBuffer();
+        res.append("-- TimeStampResp:");
+        res.append("\nstatus:  ");
+        res.append(status);
+        res.append("\ntimeStampToken:  ");
+        res.append(timeStampToken);
+        res.append("\n-- TimeStampResp End\n");
+        return res.toString();
+    }
+    
+    /**
+     * @return Returns the status.
+     */
+    public PKIStatusInfo getStatus() {
+        return status;
+    }
+
+    /**
+     * @return Returns the timeStampToken.
+     */
+    public ContentInfo getTimeStampToken() {
+        return timeStampToken;
+    }
+    
+    public static final ASN1Sequence ASN1 = new ASN1Sequence(new ASN1Type[] {
+            PKIStatusInfo.ASN1,     // status
+            ContentInfo.ASN1}) {    // timeStampToken
+        
+        {
+            setOptional(1);
+        }
+    
+        protected Object getDecodedObject(BerInputStream in) {
+            Object[] values = (Object[]) in.content;
+            return new TimeStampResp(
+                    (PKIStatusInfo) values[0],
+                    (ContentInfo) values[1]);
+        }
+        
+        protected void getValues(Object object, Object[] values) {
+            TimeStampResp resp = (TimeStampResp) object;
+            
+            values[0] = resp.status;
+            values[1] = resp.timeStampToken;
+        }    
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1Choice.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1Choice.java
new file mode 100644
index 0000000..603131d
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1Choice.java
@@ -0,0 +1,14 @@
+package org.bouncycastle.asn1;
+
+/**
+ * Marker interface for CHOICE objects - if you implement this in a role your
+ * own object any attempt to tag the object implicitly will convert the tag to
+ * an explicit one as the encoding rules require.
+ * <p>
+ * If you use this interface your class should also implement the getInstance
+ * pattern which takes a tag object and the tagging mode used. 
+ */
+public interface ASN1Choice
+{
+    // marker interface
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1Collection.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1Collection.java
new file mode 100644
index 0000000..a51dda1
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1Collection.java
@@ -0,0 +1,298 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.ConcurrentModificationException;
+
+// BEGIN android-note
+/*
+ * This is a new class that was synthesized from ASN1Sequence and
+ * ASN1Set, but with extra smarts about efficiently storing its
+ * elements.
+ */
+// END android-note
+
+/**
+ * Base class for collection-like <code>DERObject</code>s. Instances
+ * of this class will keep up to four elements directly, resorting to
+ * an external collection only if more elements than that need to be
+ * stored.
+ */
+public abstract class ASN1Collection
+    extends DERObject
+{
+    /** &gt;= 0; size of the collection */
+    private int size;
+
+    /** null-ok; element #0 */
+    private DEREncodable obj0;
+
+    /** null-ok; element #1 */
+    private DEREncodable obj1;
+
+    /** null-ok; element #2 */
+    private DEREncodable obj2;
+
+    /** null-ok; element #3 */
+    private DEREncodable obj3;
+
+    /** null-ok; elements #4 and higher */
+    private DEREncodable[] rest;
+
+    /**
+     * Returns the object at the postion indicated by index.
+     *
+     * @param index the index (starting at zero) of the object
+     * @return the object at the postion indicated by index
+     */
+    public final DEREncodable getObjectAt(int index) {
+        if ((index < 0) || (index >= size)) {
+            throw new IndexOutOfBoundsException(Integer.toString(index));
+        }
+                    
+        switch (index) {
+            case 0: return obj0;
+            case 1: return obj1;
+            case 2: return obj2;
+            case 3: return obj3;
+            default: return rest[index - 4];
+        }
+    }
+
+    /**
+     * Returns the number of objects in this instance.
+     *
+     * @return the number of objects in this instance
+     */
+    public final int size() {
+        return size;
+    }
+
+    /** {@inheritDoc} */
+    public final int hashCode() {
+        Enumeration e = this.getObjects();
+        int hashCode = 0;
+
+        while (e.hasMoreElements()) {
+            Object o = e.nextElement();
+            
+            if (o != null) {
+                hashCode ^= o.hashCode();
+            }
+        }
+
+        return hashCode;
+    }
+
+    /**
+     * Adds a new element to this instance.
+     * 
+     * @param obj non-null; the instance to add
+     */
+    protected void addObject(DEREncodable obj) {
+        if (obj == null) {
+            throw new NullPointerException("obj == null");
+        }
+
+        int sz = size;
+        
+        switch (sz) {
+            case 0: obj0 = obj; break;
+            case 1: obj1 = obj; break;
+            case 2: obj2 = obj; break;
+            case 3: obj3 = obj; break;
+            case 4: {
+                // Initial allocation of rest.
+                rest = new DEREncodable[5];
+                rest[0] = obj;
+                break;
+            }
+            default: {
+                int index = sz - 4;
+                if (index >= rest.length) {
+                    // Grow rest.
+                    DEREncodable[] newRest = new DEREncodable[index * 2 + 10];
+                    System.arraycopy(rest, 0, newRest, 0, rest.length);
+                    rest = newRest;
+                }
+                rest[index] = obj;
+                break;
+            }
+        }
+
+        size++;
+    }
+
+    /**
+     * Sets the element at a given index (used by {@link #sort}).
+     * 
+     * @param obj non-null; the object to set
+     * @param index &gt;= 0; the index
+     */
+    private void setObjectAt(DEREncodable obj, int index) {
+        switch (index) {
+            case 0: obj0 = obj; break;
+            case 1: obj1 = obj; break;
+            case 2: obj2 = obj; break;
+            case 3: obj3 = obj; break;
+            default: {
+                rest[index - 4] = obj;
+                break;
+            }
+        }
+    }
+
+    /**
+     * Encodes this instance to the given stream.
+     * 
+     * @param out non-null; stream to encode to
+     */
+    /*package*/ abstract void encode(DEROutputStream out) throws IOException;
+
+    /**
+     * Gets an enumeration of all the objects in this collection.
+     * 
+     * @return non-null; the enumeration
+     */
+    public final Enumeration getObjects() {
+        return new ASN1CollectionEnumeration();
+    }
+
+    /**
+     * Associated enumeration class.
+     */
+    private class ASN1CollectionEnumeration implements Enumeration {
+        /** original size; used for modification detection */
+        private final int origSize = size;
+
+        /** &gt;= 0; current cursor */
+        private int at = 0;
+
+        /** {@inheritDoc} */
+        public boolean hasMoreElements() {
+            if (size != origSize) {
+                throw new ConcurrentModificationException();
+            }
+
+            return at < origSize;
+        }
+
+        /** {@inheritDoc} */
+        public Object nextElement() {
+            if (size != origSize) {
+                throw new ConcurrentModificationException();
+            }
+
+            switch (at++) {
+                case 0: return obj0;
+                case 1: return obj1;
+                case 2: return obj2;
+                case 3: return obj3;
+                default: return rest[at - 5];
+            }
+        }
+    }
+
+    /**
+     * Sorts the elements in this instance.
+     */
+    protected void sort() {
+        if (size <= 1) {
+            return;
+        }
+
+        boolean swapped = true;
+
+        // TODO: This is bubble sort. Probably not the best choice.
+        while (swapped) {
+            int index = 0;
+            byte[] a = getEncoded(getObjectAt(0));
+                
+            swapped = false;
+                
+            while (index != size - 1) {
+                int nextIndex = index + 1;
+                byte[] b = getEncoded(getObjectAt(nextIndex));
+
+                if (lessThanOrEqual(a, b)) {
+                    a = b;
+                } else {
+                    DEREncodable o = getObjectAt(index);
+                    
+                    setObjectAt(getObjectAt(nextIndex), index);
+                    setObjectAt(o, nextIndex);
+
+                    swapped = true;
+                }
+
+                index++;
+            }
+        }
+    }
+    
+    /**
+     * Returns true if a <= b (arrays are assumed padded with zeros).
+     */
+    private static boolean lessThanOrEqual(byte[] a, byte[] b) {
+        if (a.length <= b.length) {
+            for (int i = 0; i != a.length; i++) {
+                int l = a[i] & 0xff;
+                int r = b[i] & 0xff;
+                 
+                if (r > l) {
+                    return true;
+                } else if (l > r) {
+                    return false;
+                }
+            }
+
+            return true;
+        } else {
+            for (int i = 0; i != b.length; i++) {
+                 int l = a[i] & 0xff;
+                 int r = b[i] & 0xff;
+                 
+                 if (r > l) {
+                     return true;
+                 } else if (l > r) {
+                     return false;
+                 }
+             }
+
+             return false;
+         }
+    }
+
+    /**
+     * Gets the encoded form of an object.
+     * 
+     * @param obj non-null; object to encode
+     * @return non-null; the encoded form
+     */
+    private static byte[] getEncoded(DEREncodable obj) {
+        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+        ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+        try {
+            aOut.writeObject(obj);
+        } catch (IOException e) {
+            throw new IllegalArgumentException(
+                    "cannot encode object added to collection");
+        }
+
+        return bOut.toByteArray();
+    }
+
+    /** {@inheritDoc} */
+    public final String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append('[');
+        for (int i = 0; i < size; i++) {
+            if (i != 0) sb.append(", ");
+            sb.append(getObjectAt(i));
+        }
+        sb.append(']');
+        return sb.toString();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1Encodable.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1Encodable.java
new file mode 100644
index 0000000..2b993c5
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1Encodable.java
@@ -0,0 +1,81 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public abstract class ASN1Encodable
+    implements DEREncodable
+{
+    public static final String DER = "DER";
+    public static final String BER = "BER";
+    
+    public byte[] getEncoded() 
+        throws IOException
+    {
+        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+        ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
+        
+        aOut.writeObject(this);
+        
+        return bOut.toByteArray();
+    }
+    
+    public byte[] getEncoded(
+        String encoding) 
+        throws IOException
+    {
+        if (encoding.equals(DER))
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DEROutputStream         dOut = new DEROutputStream(bOut);
+            
+            dOut.writeObject(this);
+            
+            return bOut.toByteArray();
+        }
+        
+        return this.getEncoded();
+    }
+    
+    /**
+     * Return the DER encoding of the object, null if the DER encoding can not be made.
+     * 
+     * @return a DER byte array, null otherwise.
+     */
+    public byte[] getDEREncoded()
+    {
+        try
+        {
+            return this.getEncoded(DER);
+        }
+        catch (IOException e)
+        {
+            return null;
+        }
+    }
+    
+    public int hashCode()
+    {
+        return this.toASN1Object().hashCode();
+    }
+
+    public boolean equals(
+        Object  o)
+    {
+        if ((o == null) || !(o instanceof DEREncodable))
+        {
+            return false;
+        }
+
+        DEREncodable other = (DEREncodable)o;
+
+        return this.toASN1Object().equals(other.getDERObject());
+    }
+
+    public DERObject getDERObject()
+    {        
+        return this.toASN1Object();
+    }
+
+    public abstract DERObject toASN1Object();
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java
new file mode 100644
index 0000000..d74e56b
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java
@@ -0,0 +1,10 @@
+package org.bouncycastle.asn1;
+
+/**
+ * the parent class for this will eventually disappear. Use this one!
+ */
+public class ASN1EncodableVector
+    extends DEREncodableVector
+{
+    // migrating from DEREncodeableVector
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java
new file mode 100644
index 0000000..03f06fe
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java
@@ -0,0 +1,531 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Vector;
+
+/**
+ * a general purpose ASN.1 decoder - note: this class differs from the
+ * others in that it returns null after it has read the last object in
+ * the stream. If an ASN.1 NULL is encountered a DER/BER Null object is
+ * returned.
+ */
+public class ASN1InputStream
+    extends FilterInputStream
+    implements DERTags
+{
+    private DERObject END_OF_STREAM = new DERObject()
+    {
+        void encode(
+            DEROutputStream out)
+        throws IOException
+        {
+            throw new IOException("Eeek!");
+        }
+        public int hashCode()
+        {
+            return 0;
+        }
+        public boolean equals(
+            Object o) 
+        {
+            return o == this;
+        }
+    };
+    
+    boolean eofFound = false;
+    int     limit = Integer.MAX_VALUE;
+
+    public ASN1InputStream(
+        InputStream is)
+    {
+        super(is);
+    }
+
+    /**
+     * Create an ASN1InputStream based on the input byte array. The length of DER objects in
+     * the stream is automatically limited to the length of the input array.
+     * 
+     * @param input array containing ASN.1 encoded data.
+     */
+    public ASN1InputStream(
+        byte[] input)
+    {
+        this(new ByteArrayInputStream(input), input.length);
+    }
+    
+    /**
+     * Create an ASN1InputStream where no DER object will be longer than limit.
+     * 
+     * @param input stream containing ASN.1 encoded data.
+     * @param limit maximum size of a DER encoded object.
+     */
+    public ASN1InputStream(
+        InputStream input,
+        int         limit)
+    {
+        super(input);
+        this.limit = limit;
+    }
+    
+    protected int readLength()
+        throws IOException
+    {
+        int length = read();
+        if (length < 0)
+        {
+            throw new IOException("EOF found when length expected");
+        }
+
+        if (length == 0x80)
+        {
+            return -1;      // indefinite-length encoding
+        }
+
+        if (length > 127)
+        {
+            int size = length & 0x7f;
+
+            if (size > 4)
+            {
+                throw new IOException("DER length more than 4 bytes");
+            }
+            
+            length = 0;
+            for (int i = 0; i < size; i++)
+            {
+                int next = read();
+
+                if (next < 0)
+                {
+                    throw new IOException("EOF found reading length");
+                }
+
+                length = (length << 8) + next;
+            }
+            
+            if (length < 0)
+            {
+                throw new IOException("corrupted steam - negative length found");
+            }
+            
+            if (length >= limit)   // after all we must have read at least 1 byte
+            {
+                throw new IOException("corrupted steam - out of bounds length found");
+            }
+        }
+
+        return length;
+    }
+
+    protected void readFully(
+        byte[]  bytes)
+        throws IOException
+    {
+        int     left = bytes.length;
+        int     len;
+
+        if (left == 0)
+        {
+            return;
+        }
+
+        while ((len = read(bytes, bytes.length - left, left)) > 0)
+        {
+            if ((left -= len) == 0)
+            {
+                return;
+            }
+        }
+
+        if (left != 0)
+        {
+            throw new EOFException("EOF encountered in middle of object");
+        }
+    }
+
+    /**
+     * build an object given its tag and a byte stream to construct it
+     * from.
+     */
+    protected DERObject buildObject(
+        int       tag,
+        int       tagNo,
+        byte[]    bytes)
+        throws IOException
+    {
+        if ((tag & APPLICATION) != 0)
+        {
+            return new DERApplicationSpecific(tag, bytes);
+        }
+        
+        switch (tag)
+        {
+        case NULL:
+            // BEGIN android-changed
+            return DERNull.THE_ONE;   
+            //END android-changed
+        case SEQUENCE | CONSTRUCTED:
+            ASN1InputStream         aIn = new ASN1InputStream(bytes);
+            ASN1EncodableVector     v = new ASN1EncodableVector();
+
+            DERObject   obj = aIn.readObject();
+
+            while (obj != null)
+            {
+                v.add(obj);
+                obj = aIn.readObject();
+            }
+
+            return new DERSequence(v);
+        case SET | CONSTRUCTED:
+            aIn = new ASN1InputStream(bytes);
+            v = new ASN1EncodableVector();
+
+            obj = aIn.readObject();
+
+            while (obj != null)
+            {
+                v.add(obj);
+                obj = aIn.readObject();
+            }
+
+            return new DERSet(v, false);
+        case BOOLEAN:
+            // BEGIN android-changed
+            return DERBoolean.getInstance(bytes);
+            // END android-changed
+        case INTEGER:
+            return new DERInteger(bytes);
+        case ENUMERATED:
+            return new DEREnumerated(bytes);
+        case OBJECT_IDENTIFIER:
+            return new DERObjectIdentifier(bytes);
+        case BIT_STRING:
+            int     padBits = bytes[0];
+            byte[]  data = new byte[bytes.length - 1];
+
+            System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
+
+            return new DERBitString(data, padBits);
+        case NUMERIC_STRING:
+            return new DERNumericString(bytes);
+        case UTF8_STRING:
+            return new DERUTF8String(bytes);
+        case PRINTABLE_STRING:
+            return new DERPrintableString(bytes);
+        case IA5_STRING:
+            return new DERIA5String(bytes);
+        case T61_STRING:
+            return new DERT61String(bytes);
+        case VISIBLE_STRING:
+            return new DERVisibleString(bytes);
+        case GENERAL_STRING:
+            return new DERGeneralString(bytes);
+        case UNIVERSAL_STRING:
+            return new DERUniversalString(bytes);
+        case BMP_STRING:
+            return new DERBMPString(bytes);
+        case OCTET_STRING:
+            return new DEROctetString(bytes);
+        case OCTET_STRING | CONSTRUCTED:
+            return buildDerConstructedOctetString(bytes);
+        case UTC_TIME:
+            return new DERUTCTime(bytes);
+        case GENERALIZED_TIME:
+            return new DERGeneralizedTime(bytes);
+        default:
+            //
+            // with tagged object tag number is bottom 5 bits
+            //
+            
+            if ((tag & TAGGED) != 0)  
+            {
+                if (bytes.length == 0)        // empty tag!
+                {
+                    if ((tag & CONSTRUCTED) == 0)
+                    {
+                        // BEGIN android-changed
+                        return new DERTaggedObject(false, tagNo, DERNull.THE_ONE);
+                        // END android-changed
+                    }
+                    else
+                    {
+                        return new DERTaggedObject(false, tagNo, new DERSequence());
+                    }
+                }
+
+                //
+                // simple type - implicit... return an octet string
+                //
+                if ((tag & CONSTRUCTED) == 0)
+                {
+                    return new DERTaggedObject(false, tagNo, new DEROctetString(bytes));
+                }
+
+                aIn = new ASN1InputStream(bytes);
+
+                DEREncodable dObj = aIn.readObject();
+
+                //
+                // explicitly tagged (probably!) - if it isn't we'd have to
+                // tell from the context
+                //
+                if (aIn.available() == 0)
+                {
+                    return new DERTaggedObject(tagNo, dObj);
+                }
+
+                //
+                // another implicit object, we'll create a sequence...
+                //
+                v = new ASN1EncodableVector();
+
+                while (dObj != null)
+                {
+                    v.add(dObj);
+                    dObj = aIn.readObject();
+                }
+
+                return new DERTaggedObject(false, tagNo, new DERSequence(v));
+            }
+
+            return new DERUnknownTag(tag, bytes);
+        }
+    }
+
+    /**
+     * read a string of bytes representing an indefinite length object.
+     */
+    private byte[] readIndefiniteLengthFully()
+        throws IOException
+    {
+        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+        int                     b, b1;
+
+        b1 = read();
+
+        while ((b = read()) >= 0)
+        {
+            if (b1 == 0 && b == 0)
+            {
+                break;
+            }
+
+            bOut.write(b1);
+            b1 = b;
+        }
+
+        return bOut.toByteArray();
+    }
+
+    private BERConstructedOctetString buildConstructedOctetString()
+        throws IOException
+    {
+        Vector               octs = new Vector();
+
+        for (;;)
+        {
+            DERObject        o = readObject();
+
+            if (o == END_OF_STREAM)
+            {
+                break;
+            }
+
+            octs.addElement(o);
+        }
+
+        return new BERConstructedOctetString(octs);
+    }
+    
+    //
+    // yes, people actually do this...
+    //
+    private BERConstructedOctetString buildDerConstructedOctetString(byte[] input)
+        throws IOException
+    {
+        Vector               octs = new Vector();
+        ASN1InputStream      aIn = new ASN1InputStream(input);
+        DERObject            o;
+        
+        while ((o = aIn.readObject()) != null)
+        {
+            octs.addElement(o);
+        }
+    
+        return new BERConstructedOctetString(octs);
+    }
+
+    public DERObject readObject()
+        throws IOException
+    {
+        int tag = read();
+        if (tag == -1)
+        {
+            if (eofFound)
+            {
+                throw new EOFException("attempt to read past end of file.");
+            }
+
+            eofFound = true;
+
+            return null;
+        }
+    
+        int tagNo = 0;
+        
+        if ((tag & TAGGED) != 0)  
+        {
+            tagNo = readTagNumber(tag);
+        }
+        
+        int     length = readLength();
+
+        if (length < 0)    // indefinite length method
+        {
+            switch (tag)
+            {
+            case NULL:
+                // BEGIN android-changed
+                return BERNull.THE_ONE;
+                // END android-changed
+            case SEQUENCE | CONSTRUCTED:
+                ASN1EncodableVector  v = new ASN1EncodableVector();
+    
+                for (;;)
+                {
+                    DERObject   obj = readObject();
+
+                    if (obj == END_OF_STREAM)
+                    {
+                        break;
+                    }
+
+                    v.add(obj);
+                }
+                return new BERSequence(v);
+            case SET | CONSTRUCTED:
+                v = new ASN1EncodableVector();
+    
+                for (;;)
+                {
+                    DERObject   obj = readObject();
+
+                    if (obj == END_OF_STREAM)
+                    {
+                        break;
+                    }
+
+                    v.add(obj);
+                }
+                return new BERSet(v, false);
+            case OCTET_STRING | CONSTRUCTED:
+                return buildConstructedOctetString();
+            default:
+                //
+                // with tagged object tag number is bottom 5 bits
+                //
+                if ((tag & TAGGED) != 0)  
+                {
+                    //
+                    // simple type - implicit... return an octet string
+                    //
+                    if ((tag & CONSTRUCTED) == 0)
+                    {
+                        byte[]  bytes = readIndefiniteLengthFully();
+
+                        return new BERTaggedObject(false, tagNo, new DEROctetString(bytes));
+                    }
+
+                    //
+                    // either constructed or explicitly tagged
+                    //
+                    DERObject        dObj = readObject();
+
+                    if (dObj == END_OF_STREAM)     // empty tag!
+                    {
+                        return new DERTaggedObject(tagNo);
+                    }
+
+                    DERObject       next = readObject();
+
+                    //
+                    // explicitly tagged (probably!) - if it isn't we'd have to
+                    // tell from the context
+                    //
+                    if (next == END_OF_STREAM)
+                    {
+                        return new BERTaggedObject(tagNo, dObj);
+                    }
+
+                    //
+                    // another implicit object, we'll create a sequence...
+                    //
+                    v = new ASN1EncodableVector();
+
+                    v.add(dObj);
+
+                    do
+                    {
+                        v.add(next);
+                        next = readObject();
+                    }
+                    while (next != END_OF_STREAM);
+
+                    return new BERTaggedObject(false, tagNo, new BERSequence(v));
+                }
+
+                throw new IOException("unknown BER object encountered");
+            }
+        }
+        else
+        {
+            if (tag == 0 && length == 0)    // end of contents marker.
+            {
+                return END_OF_STREAM;
+            }
+
+            byte[]  bytes = new byte[length];
+    
+            readFully(bytes);
+    
+            return buildObject(tag, tagNo, bytes);
+        }
+    }
+
+    private int readTagNumber(int tag) 
+        throws IOException
+    {
+        int tagNo = tag & 0x1f;
+
+        if (tagNo == 0x1f)
+        {
+            int b = read();
+
+            tagNo = 0;
+
+            while ((b >= 0) && ((b & 0x80) != 0))
+            {
+                tagNo |= (b & 0x7f);
+                tagNo <<= 7;
+                b = read();
+            }
+
+            if (b < 0)
+            {
+                eofFound = true;
+                throw new EOFException("EOF found inside tag value.");
+            }
+            
+            tagNo |= (b & 0x7f);
+        }
+        
+        return tagNo;
+    }
+}
+
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1Null.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1Null.java
new file mode 100644
index 0000000..dcb823d
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1Null.java
@@ -0,0 +1,40 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * A NULL object.
+ */
+public abstract class ASN1Null
+    extends DERObject
+{
+    // BEGIN android-changed
+    /*package*/ ASN1Null()
+    {
+    }
+    // END android-changed
+
+    public int hashCode()
+    {
+        return 0;
+    }
+
+    public boolean equals(
+        Object o)
+    {
+        if ((o == null) || !(o instanceof ASN1Null))
+        {
+            return false;
+        }
+        
+        return true;
+    }
+
+    abstract void encode(DEROutputStream out)
+        throws IOException;
+
+    public String toString()
+    {
+      return "NULL";
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java
new file mode 100644
index 0000000..a65d268
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java
@@ -0,0 +1,147 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+import org.bouncycastle.util.encoders.Hex;
+
+public abstract class ASN1OctetString
+    extends DERObject
+{
+    byte[]  string;
+
+    /**
+     * return an Octet String from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want.
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *              be converted.
+     */
+    public static ASN1OctetString getInstance(
+        ASN1TaggedObject    obj,
+        boolean             explicit)
+    {
+        return getInstance(obj.getObject());
+    }
+    
+    /**
+     * return an Octet String from the given object.
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static ASN1OctetString getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof ASN1OctetString)
+        {
+            return (ASN1OctetString)obj;
+        }
+
+        if (obj instanceof ASN1TaggedObject)
+        {
+            return getInstance(((ASN1TaggedObject)obj).getObject());
+        }
+
+        if (obj instanceof ASN1Sequence)
+        {
+            Vector      v = new Vector();
+            Enumeration e = ((ASN1Sequence)obj).getObjects();
+
+            while (e.hasMoreElements())
+            {
+                v.addElement(e.nextElement());
+            }
+
+            return new BERConstructedOctetString(v);
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * @param string the octets making up the octet string.
+     */
+    public ASN1OctetString(
+        byte[]  string)
+    {
+        this.string = string;
+    }
+
+    public ASN1OctetString(
+        DEREncodable obj)
+    {
+        try
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DEROutputStream         dOut = new DEROutputStream(bOut);
+
+            dOut.writeObject(obj);
+            dOut.close();
+
+            this.string = bOut.toByteArray();
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("Error processing object : " + e.toString());
+        }
+    }
+
+    public byte[] getOctets()
+    {
+        return string;
+    }
+
+    public int hashCode()
+    {
+        byte[]  b = this.getOctets();
+        int     value = 0;
+
+        for (int i = 0; i != b.length; i++)
+        {
+            value ^= (b[i] & 0xff) << (i % 4);
+        }
+
+        return value;
+    }
+
+    public boolean equals(
+        Object  o)
+    {
+        if (!(o instanceof DEROctetString))
+        {
+            return false;
+        }
+
+        DEROctetString  other = (DEROctetString)o;
+
+        byte[] b1 = other.getOctets();
+        byte[] b2 = this.getOctets();
+
+        if (b1.length != b2.length)
+        {
+            return false;
+        }
+
+        for (int i = 0; i != b1.length; i++)
+        {
+            if (b1[i] != b2[i])
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    abstract void encode(DEROutputStream out)
+        throws IOException;
+
+    public String toString()
+    {
+      return "#"+new String(Hex.encode(string));
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1OutputStream.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1OutputStream.java
new file mode 100644
index 0000000..5897d09
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1OutputStream.java
@@ -0,0 +1,36 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class ASN1OutputStream
+    extends DEROutputStream
+{
+    public ASN1OutputStream(
+        OutputStream    os)
+    {
+        super(os);
+    }
+
+    public void writeObject(
+        Object    obj)
+        throws IOException
+    {
+        if (obj == null)
+        {
+            writeNull();
+        }
+        else if (obj instanceof DERObject)
+        {
+            ((DERObject)obj).encode(this);
+        }
+        else if (obj instanceof DEREncodable)
+        {
+            ((DEREncodable)obj).getDERObject().encode(this);
+        }
+        else
+        {
+            throw new IOException("object not ASN1Encodable");
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java
new file mode 100644
index 0000000..400b1dc
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java
@@ -0,0 +1,216 @@
+package org.bouncycastle.asn1;
+
+// BEGIN android-removed
+//import java.io.IOException;
+// END android-removed
+import java.util.Enumeration;
+// BEGIN android-removed
+//import java.util.Vector;
+// END android-removed
+
+// BEGIN android-note
+// Changed inheritence of class.
+// END android-note
+
+public abstract class ASN1Sequence
+    extends ASN1Collection
+{
+    // BEGIN android-removed
+    // private Vector seq = new Vector();
+    // END android-removed
+
+    /**
+     * return an ASN1Sequence from the given object.
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static ASN1Sequence getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof ASN1Sequence)
+        {
+            return (ASN1Sequence)obj;
+        }
+
+        throw new IllegalArgumentException("unknown object in getInstance");
+    }
+
+    /**
+     * Return an ASN1 sequence from a tagged object. There is a special
+     * case here, if an object appears to have been explicitly tagged on 
+     * reading but we were expecting it to be implictly tagged in the 
+     * normal course of events it indicates that we lost the surrounding
+     * sequence - so we need to add it back (this will happen if the tagged
+     * object is a sequence that contains other sequences). If you are
+     * dealing with implicitly tagged sequences you really <b>should</b>
+     * be using this method.
+     *
+     * @param obj the tagged object.
+     * @param explicit true if the object is meant to be explicitly tagged,
+     *          false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *          be converted.
+     */
+    public static ASN1Sequence getInstance(
+        ASN1TaggedObject    obj,
+        boolean             explicit)
+    {
+        if (explicit)
+        {
+            if (!obj.isExplicit())
+            {
+                throw new IllegalArgumentException("object implicit - explicit expected.");
+            }
+
+            return (ASN1Sequence)obj.getObject();
+        }
+        else
+        {
+            //
+            // constructed object which appears to be explicitly tagged
+            // when it should be implicit means we have to add the
+            // surrounding sequence.
+            //
+            if (obj.isExplicit())
+            {
+                if (obj instanceof BERTaggedObject)
+                {
+                    return new BERSequence(obj.getObject());
+                }
+                else
+                {
+                    return new DERSequence(obj.getObject());
+                }
+            }
+            else
+            {
+                if (obj.getObject() instanceof ASN1Sequence)
+                {
+                    return (ASN1Sequence)obj.getObject();
+                }
+            }
+        }
+
+        throw new IllegalArgumentException(
+                "unknown object in getInstanceFromTagged");
+    }
+
+    // BEGIN android-removed
+    //public Enumeration getObjects()
+    //{
+    //    return seq.elements();
+    //}
+
+    ///**
+    // * return the object at the sequence postion indicated by index.
+    // *
+    // * @param index the sequence number (starting at zero) of the object
+    // * @return the object at the sequence postion indicated by index.
+    // */
+    //public DEREncodable getObjectAt(
+    //    int index)
+    //{
+    //    return (DEREncodable)seq.elementAt(index);
+    //}
+
+    ///**
+    // * return the number of objects in this sequence.
+    // *
+    // * @return the number of objects in this sequence.
+    // */
+    //public int size()
+    //{
+    //    return seq.size();
+    //}
+
+    //public int hashCode()
+    //{
+    //    Enumeration             e = this.getObjects();
+    //    int                     hashCode = 0;
+
+    //    while (e.hasMoreElements())
+    //    {
+    //        Object    o = e.nextElement();
+    //        
+    //        if (o != null)
+    //        {
+    //            hashCode ^= o.hashCode();
+    //        }
+    //    }
+
+    //    return hashCode;
+    //}
+    // END android-removed
+
+    public boolean equals(
+        Object  o)
+    {
+        if (o == this)
+        {
+            return true;
+        }
+        
+        if (!(o instanceof DEREncodable))
+        {
+            return false;
+        }
+
+        DERObject      dObj = ((DEREncodable)o).getDERObject();
+        
+        if (!(dObj instanceof ASN1Sequence))
+        {
+            return false;
+        }
+        
+        ASN1Sequence   other = (ASN1Sequence)dObj;
+
+        if (this.size() != other.size())
+        {
+            return false;
+        }
+
+        Enumeration s1 = this.getObjects();
+        Enumeration s2 = other.getObjects();
+
+        while (s1.hasMoreElements())
+        {
+            Object  o1 = s1.nextElement();
+            Object  o2 = s2.nextElement();
+
+            if (o1 != null && o2 != null)
+            {
+                if (!o1.equals(o2))
+                {
+                    return false;
+                }
+            }
+            else if (o1 == null && o2 == null)
+            {
+                continue;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    // BEGIN android-removed
+    //protected void addObject(
+    //    DEREncodable obj)
+    //{
+    //    seq.addElement(obj);
+    //}
+
+    //abstract void encode(DEROutputStream out)
+    //    throws IOException;
+
+    //public String toString() 
+    //{
+    //  return seq.toString();
+    //}
+    // END android-removed
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1Set.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1Set.java
new file mode 100644
index 0000000..9e6c55f
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1Set.java
@@ -0,0 +1,318 @@
+package org.bouncycastle.asn1;
+
+// BEGIN android-removed
+//import java.io.ByteArrayOutputStream;
+//import java.io.IOException;
+// END android-removed
+import java.util.Enumeration;
+// BEGIN android-removed
+//import java.util.Vector;
+// END android-removed;
+
+// BEGIN android-note
+// Changed inheritence of class.
+// END android-note
+
+abstract public class ASN1Set
+    extends ASN1Collection
+{
+    // BEGIN android-removed
+    //protected Vector set = new Vector();
+    // END android-removed
+
+    /**
+     * return an ASN1Set from the given object.
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static ASN1Set getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof ASN1Set)
+        {
+            return (ASN1Set)obj;
+        }
+
+        throw new IllegalArgumentException("unknown object in getInstance");
+    }
+
+    /**
+     * Return an ASN1 set from a tagged object. There is a special
+     * case here, if an object appears to have been explicitly tagged on 
+     * reading but we were expecting it to be implictly tagged in the 
+     * normal course of events it indicates that we lost the surrounding
+     * set - so we need to add it back (this will happen if the tagged
+     * object is a sequence that contains other sequences). If you are
+     * dealing with implicitly tagged sets you really <b>should</b>
+     * be using this method.
+     *
+     * @param obj the tagged object.
+     * @param explicit true if the object is meant to be explicitly tagged
+     *          false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *          be converted.
+     */
+    public static ASN1Set getInstance(
+        ASN1TaggedObject    obj,
+        boolean             explicit)
+    {
+        if (explicit)
+        {
+            if (!obj.isExplicit())
+            {
+                throw new IllegalArgumentException("object implicit - explicit expected.");
+            }
+
+            return (ASN1Set)obj.getObject();
+        }
+        else
+        {
+            //
+            // constructed object which appears to be explicitly tagged
+            // and it's really implicit means we have to add the
+            // surrounding sequence.
+            //
+            if (obj.isExplicit())
+            {
+                ASN1Set    set = new DERSet(obj.getObject());
+
+                return set;
+            }
+            else
+            {
+                if (obj.getObject() instanceof ASN1Set)
+                {
+                    return (ASN1Set)obj.getObject();
+                }
+
+                //
+                // in this case the parser returns a sequence, convert it
+                // into a set.
+                //
+                ASN1EncodableVector  v = new ASN1EncodableVector();
+
+                if (obj.getObject() instanceof ASN1Sequence)
+                {
+                    ASN1Sequence s = (ASN1Sequence)obj.getObject();
+                    Enumeration e = s.getObjects();
+
+                    while (e.hasMoreElements())
+                    {
+                        v.add((DEREncodable)e.nextElement());
+                    }
+
+                    return new DERSet(v, false);
+                }
+            }
+        }
+
+        throw new IllegalArgumentException(
+                    "unknown object in getInstanceFromTagged");
+    }
+
+    public ASN1Set()
+    {
+    }
+
+    // BEGIN android-removed
+    //public Enumeration getObjects()
+    //{
+    //    return set.elements();
+    //}
+
+    ///**
+    // * return the object at the set postion indicated by index.
+    // *
+    // * @param index the set number (starting at zero) of the object
+    // * @return the object at the set postion indicated by index.
+    // */
+    //public DEREncodable getObjectAt(
+    //    int index)
+    //{
+    //    return (DEREncodable)set.elementAt(index);
+    //}
+
+    ///**
+    // * return the number of objects in this set.
+    // *
+    // * @return the number of objects in this set.
+    // */
+    //public int size()
+    //{
+    //    return set.size();
+    //}
+
+    //public int hashCode()
+    //{
+    //    Enumeration             e = this.getObjects();
+    //    int                     hashCode = 0;
+
+    //    while (e.hasMoreElements())
+    //    {
+    //        hashCode ^= e.nextElement().hashCode();
+    //    }
+
+    //    return hashCode;
+    //}
+    // END android-removed
+
+    public boolean equals(
+        Object  o)
+    {
+        if (o == this)
+        {
+            return true;
+        }
+        
+        if (!(o instanceof DEREncodable))
+        {
+            return false;
+        }
+
+        DERObject      dObj = ((DEREncodable)o).getDERObject();
+        
+        if (!(dObj instanceof ASN1Set))
+        {
+            return false;
+        }
+
+        ASN1Set   other = (ASN1Set)dObj;
+
+        if (this.size() != other.size())
+        {
+            return false;
+        }
+
+        Enumeration s1 = this.getObjects();
+        Enumeration s2 = other.getObjects();
+
+        while (s1.hasMoreElements())
+        {
+            if (!s1.nextElement().equals(s2.nextElement()))
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    // BEGIN android-removed
+    ///**
+    // * return true if a <= b (arrays are assumed padded with zeros).
+    // */
+    //private boolean lessThanOrEqual(
+    //     byte[] a,
+    //     byte[] b)
+    //{
+    //     if (a.length <= b.length)
+    //     {
+    //         for (int i = 0; i != a.length; i++)
+    //         {
+    //             int    l = a[i] & 0xff;
+    //             int    r = b[i] & 0xff;
+    //             
+    //             if (r > l)
+    //             {
+    //                 return true;
+    //             }
+    //             else if (l > r)
+    //             {
+    //                 return false;
+    //             }
+    //         }
+
+    //         return true;
+    //     }
+    //     else
+    //     {
+    //         for (int i = 0; i != b.length; i++)
+    //         {
+    //             int    l = a[i] & 0xff;
+    //             int    r = b[i] & 0xff;
+    //             
+    //             if (r > l)
+    //             {
+    //                 return true;
+    //             }
+    //             else if (l > r)
+    //             {
+    //                 return false;
+    //             }
+    //         }
+
+    //         return false;
+    //     }
+    //}
+
+    //private byte[] getEncoded(
+    //    DEREncodable obj)
+    //{
+    //    ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+    //    ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
+
+    //    try
+    //    {
+    //        aOut.writeObject(obj);
+    //    }
+    //    catch (IOException e)
+    //    {
+    //        throw new IllegalArgumentException("cannot encode object added to SET");
+    //    }
+
+    //    return bOut.toByteArray();
+    //}
+
+    //protected void sort()
+    //{
+    //    if (set.size() > 1)
+    //    {
+    //        boolean    swapped = true;
+
+    //        while (swapped)
+    //        {
+    //            int    index = 0;
+    //            byte[] a = getEncoded((DEREncodable)set.elementAt(0));
+    //            
+    //            swapped = false;
+    //            
+    //            while (index != set.size() - 1)
+    //            {
+    //                byte[] b = getEncoded((DEREncodable)set.elementAt(index + 1));
+
+    //                if (lessThanOrEqual(a, b))
+    //                {
+    //                    a = b;
+    //                }
+    //                else
+    //                {
+    //                    Object  o = set.elementAt(index);
+
+    //                    set.setElementAt(set.elementAt(index + 1), index);
+    //                    set.setElementAt(o, index + 1);
+
+    //                    swapped = true;
+    //                }
+
+    //                index++;
+    //            }
+    //        }
+    //    }
+    //}
+
+    //protected void addObject(
+    //    DEREncodable obj)
+    //{
+    //    set.addElement(obj);
+    //}
+
+    //abstract void encode(DEROutputStream out)
+    //        throws IOException;
+
+    //public String toString() 
+    //{
+    //  return set.toString();
+    //}
+    // END android-removed
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java
new file mode 100644
index 0000000..5d6a2a4
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java
@@ -0,0 +1,177 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * ASN.1 TaggedObject - in ASN.1 nottation this is any object proceeded by
+ * a [n] where n is some number - these are assume to follow the construction
+ * rules (as with sequences).
+ */
+public abstract class ASN1TaggedObject
+    extends DERObject
+{
+    int             tagNo;
+    boolean         empty = false;
+    boolean         explicit = true;
+    DEREncodable    obj = null;
+
+    static public ASN1TaggedObject getInstance(
+        ASN1TaggedObject    obj,
+        boolean             explicit)
+    {
+        if (explicit)
+        {
+            return (ASN1TaggedObject)obj.getObject();
+        }
+
+        throw new IllegalArgumentException("implicitly tagged tagged object");
+    }
+
+    static public ASN1TaggedObject getInstance(
+        Object obj) 
+    {
+        if (obj == null || obj instanceof ASN1TaggedObject) 
+        {
+                return (ASN1TaggedObject)obj;
+        }
+
+        throw new IllegalArgumentException("unknown object in getInstance");
+    }
+
+    /**
+     * Create a tagged object in the explicit style.
+     * 
+     * @param tagNo the tag number for this object.
+     * @param obj the tagged object.
+     */
+    public ASN1TaggedObject(
+        int             tagNo,
+        DEREncodable    obj)
+    {
+        this.explicit = true;
+        this.tagNo = tagNo;
+        this.obj = obj;
+    }
+
+    /**
+     * Create a tagged object with the style given by the value of explicit.
+     * <p>
+     * If the object implements ASN1Choice the tag style will always be changed
+     * to explicit in accordance with the ASN.1 encoding rules.
+     * </p>
+     * @param explicit true if the object is explicitly tagged.
+     * @param tagNo the tag number for this object.
+     * @param obj the tagged object.
+     */
+    public ASN1TaggedObject(
+        boolean         explicit,
+        int             tagNo,
+        DEREncodable    obj)
+    {
+        if (obj instanceof ASN1Choice)
+        {
+            this.explicit = true;
+        }
+        else
+        {
+            this.explicit = explicit;
+        }
+        
+        this.tagNo = tagNo;
+        this.obj = obj;
+    }
+    
+    public boolean equals(
+        Object o)
+    {
+        if (!(o instanceof ASN1TaggedObject))
+        {
+            return false;
+        }
+        
+        ASN1TaggedObject other = (ASN1TaggedObject)o;
+        
+        if (tagNo != other.tagNo || empty != other.empty || explicit != other.explicit)
+        {
+            return false;
+        }
+        
+        if(obj == null)
+        {
+            if(other.obj != null)
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if(!(obj.equals(other.obj)))
+            {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+    
+    public int hashCode()
+    {
+        int code = tagNo;
+
+        if (obj != null)
+        {
+            code ^= obj.hashCode();
+        }
+
+        return code;
+    }
+
+    public int getTagNo()
+    {
+        return tagNo;
+    }
+
+    /**
+     * return whether or not the object may be explicitly tagged. 
+     * <p>
+     * Note: if the object has been read from an input stream, the only
+     * time you can be sure if isExplicit is returning the true state of
+     * affairs is if it returns false. An implicitly tagged object may appear
+     * to be explicitly tagged, so you need to understand the context under
+     * which the reading was done as well, see getObject below.
+     */
+    public boolean isExplicit()
+    {
+        return explicit;
+    }
+
+    public boolean isEmpty()
+    {
+        return empty;
+    }
+
+    /**
+     * return whatever was following the tag.
+     * <p>
+     * Note: tagged objects are generally context dependent if you're
+     * trying to extract a tagged object you should be going via the
+     * appropriate getInstance method.
+     */
+    public DERObject getObject()
+    {
+        if (obj != null)
+        {
+            return obj.getDERObject();
+        }
+
+        return null;
+    }
+
+    abstract void encode(DEROutputStream  out)
+        throws IOException;
+
+    public String toString()
+    {
+        return "[" + tagNo + "]" + obj;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/BERConstructedOctetString.java b/libcore/security/src/main/java/org/bouncycastle/asn1/BERConstructedOctetString.java
new file mode 100644
index 0000000..c9518a6
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/BERConstructedOctetString.java
@@ -0,0 +1,172 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+public class BERConstructedOctetString
+    extends DEROctetString
+{
+    /**
+     * convert a vector of octet strings into a single byte string
+     */
+    static private byte[] toBytes(
+        Vector  octs)
+    {
+        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+
+        for (int i = 0; i != octs.size(); i++)
+        {
+            try
+            {
+                DEROctetString  o = (DEROctetString)octs.elementAt(i);
+
+                bOut.write(o.getOctets());
+            }
+            catch (ClassCastException e)
+            {
+                throw new IllegalArgumentException(octs.elementAt(i).getClass().getName() + " found in input should only contain DEROctetString");
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("exception converting octets " + e.toString());
+            }
+        }
+
+        return bOut.toByteArray();
+    }
+
+    private Vector  octs;
+
+    /**
+     * @param string the octets making up the octet string.
+     */
+    public BERConstructedOctetString(
+        byte[]  string)
+    {
+        super(string);
+    }
+
+    public BERConstructedOctetString(
+        Vector  octs)
+    {
+        super(toBytes(octs));
+
+        this.octs = octs;
+    }
+
+    public BERConstructedOctetString(
+        DERObject  obj)
+    {
+        super(obj);
+    }
+
+    public BERConstructedOctetString(
+        DEREncodable  obj)
+    {
+        super(obj.getDERObject());
+    }
+
+    public byte[] getOctets()
+    {
+        return string;
+    }
+
+    /**
+     * return the DER octets that make up this string.
+     */
+    public Enumeration getObjects()
+    {
+        if (octs == null)
+        {
+            return generateOcts().elements();
+        }
+
+        return octs.elements();
+    }
+
+    private Vector generateOcts()
+    {
+        int     start = 0;
+        int     end = 0;
+        Vector  vec = new Vector();
+
+        while ((end + 1) < string.length)
+        {
+            if (string[end] == 0 && string[end + 1] == 0)
+            {
+                byte[]  nStr = new byte[end - start + 1];
+
+                System.arraycopy(string, start, nStr, 0, nStr.length);
+
+                vec.addElement(new DEROctetString(nStr));
+                start = end + 1;
+            }
+            end++;
+        }
+
+        byte[]  nStr = new byte[string.length - start];
+
+        System.arraycopy(string, start, nStr, 0, nStr.length);
+
+        vec.addElement(new DEROctetString(nStr));
+
+        return vec;
+    }
+
+    public void encode(
+        DEROutputStream out)
+        throws IOException
+    {
+        if (out instanceof ASN1OutputStream || out instanceof BEROutputStream)
+        {
+            out.write(CONSTRUCTED | OCTET_STRING);
+
+            out.write(0x80);
+
+            //
+            // write out the octet array
+            //
+            if (octs != null)
+            {
+                for (int i = 0; i != octs.size(); i++)
+                {
+                    out.writeObject(octs.elementAt(i));
+                }
+            }
+            else
+            {
+                int     start = 0;
+                int     end = 0;
+
+                while ((end + 1) < string.length)
+                {
+                    if (string[end] == 0 && string[end + 1] == 0)
+                    {
+                        byte[]  nStr = new byte[end - start + 1];
+
+                        System.arraycopy(string, start, nStr, 0, nStr.length);
+
+                        out.writeObject(new DEROctetString(nStr));
+                        start = end + 1;
+                    }
+                    end++;
+                }
+
+                byte[]  nStr = new byte[string.length - start];
+
+                System.arraycopy(string, start, nStr, 0, nStr.length);
+
+                out.writeObject(new DEROctetString(nStr));
+            }
+
+            out.write(0x00);
+            out.write(0x00);
+        }
+        else
+        {
+            super.encode(out);
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/BERConstructedSequence.java b/libcore/security/src/main/java/org/bouncycastle/asn1/BERConstructedSequence.java
new file mode 100644
index 0000000..998eaeb
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/BERConstructedSequence.java
@@ -0,0 +1,37 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ * @deprecated use BERSequence
+ */
+public class BERConstructedSequence
+    extends DERConstructedSequence
+{
+    /*
+     */
+    void encode(
+        DEROutputStream out)
+        throws IOException
+    {
+        if (out instanceof ASN1OutputStream || out instanceof BEROutputStream)
+        {
+            out.write(SEQUENCE | CONSTRUCTED);
+            out.write(0x80);
+            
+            Enumeration e = getObjects();
+            while (e.hasMoreElements())
+            {
+                out.writeObject(e.nextElement());
+            }
+        
+            out.write(0x00);
+            out.write(0x00);
+        }
+        else
+        {
+            super.encode(out);
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/BERInputStream.java b/libcore/security/src/main/java/org/bouncycastle/asn1/BERInputStream.java
new file mode 100644
index 0000000..088f915
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/BERInputStream.java
@@ -0,0 +1,209 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Vector;
+
+/**
+ * @deprecated use ASN1InputStream
+ */
+public class BERInputStream
+    extends DERInputStream
+{
+    private DERObject END_OF_STREAM = new DERObject()
+    {
+                                        void encode(
+                                            DEROutputStream out)
+                                        throws IOException
+                                        {
+                                            throw new IOException("Eeek!");
+                                        }
+                                        public int hashCode()
+                                        {
+                                            return 0;
+                                        }
+                                        public boolean equals(
+                                            Object o) 
+                                        {
+                                            return o == this;
+                                        }
+                                    };
+    public BERInputStream(
+        InputStream is)
+    {
+        super(is);
+    }
+
+    /**
+     * read a string of bytes representing an indefinite length object.
+     */
+    private byte[] readIndefiniteLengthFully()
+        throws IOException
+    {
+        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+        int                     b, b1;
+
+        b1 = read();
+
+        while ((b = read()) >= 0)
+        {
+            if (b1 == 0 && b == 0)
+            {
+                break;
+            }
+
+            bOut.write(b1);
+            b1 = b;
+        }
+
+        return bOut.toByteArray();
+    }
+
+    private BERConstructedOctetString buildConstructedOctetString()
+        throws IOException
+    {
+        Vector               octs = new Vector();
+
+        for (;;)
+        {
+            DERObject        o = readObject();
+
+            if (o == END_OF_STREAM)
+            {
+                break;
+            }
+
+            octs.addElement(o);
+        }
+
+        return new BERConstructedOctetString(octs);
+    }
+
+    public DERObject readObject()
+        throws IOException
+    {
+        int tag = read();
+        if (tag == -1)
+        {
+            throw new EOFException();
+        }
+    
+        int     length = readLength();
+
+        if (length < 0)    // indefinite length method
+        {
+            switch (tag)
+            {
+            case NULL:
+                return null;
+            case SEQUENCE | CONSTRUCTED:
+                BERConstructedSequence  seq = new BERConstructedSequence();
+    
+                for (;;)
+                {
+                    DERObject   obj = readObject();
+
+                    if (obj == END_OF_STREAM)
+                    {
+                        break;
+                    }
+
+                    seq.addObject(obj);
+                }
+                return seq;
+            case OCTET_STRING | CONSTRUCTED:
+                return buildConstructedOctetString();
+            case SET | CONSTRUCTED:
+                ASN1EncodableVector  v = new ASN1EncodableVector();
+    
+                for (;;)
+                {
+                    DERObject   obj = readObject();
+
+                    if (obj == END_OF_STREAM)
+                    {
+                        break;
+                    }
+
+                    v.add(obj);
+                }
+                return new BERSet(v);
+            default:
+                //
+                // with tagged object tag number is bottom 5 bits
+                //
+                if ((tag & TAGGED) != 0)  
+                {
+                    if ((tag & 0x1f) == 0x1f)
+                    {
+                        throw new IOException("unsupported high tag encountered");
+                    }
+
+                    //
+                    // simple type - implicit... return an octet string
+                    //
+                    if ((tag & CONSTRUCTED) == 0)
+                    {
+                        byte[]  bytes = readIndefiniteLengthFully();
+
+                        return new BERTaggedObject(false, tag & 0x1f, new DEROctetString(bytes));
+                    }
+
+                    //
+                    // either constructed or explicitly tagged
+                    //
+                    DERObject        dObj = readObject();
+
+                    if (dObj == END_OF_STREAM)     // empty tag!
+                    {
+                        return new DERTaggedObject(tag & 0x1f);
+                    }
+
+                    DERObject       next = readObject();
+
+                    //
+                    // explicitly tagged (probably!) - if it isn't we'd have to
+                    // tell from the context
+                    //
+                    if (next == END_OF_STREAM)
+                    {
+                        return new BERTaggedObject(tag & 0x1f, dObj);
+                    }
+
+                    //
+                    // another implicit object, we'll create a sequence...
+                    //
+                    seq = new BERConstructedSequence();
+
+                    seq.addObject(dObj);
+
+                    do
+                    {
+                        seq.addObject(next);
+                        next = readObject();
+                    }
+                    while (next != END_OF_STREAM);
+
+                    return new BERTaggedObject(false, tag & 0x1f, seq);
+                }
+
+                throw new IOException("unknown BER object encountered");
+            }
+        }
+        else
+        {
+            if (tag == 0 && length == 0)    // end of contents marker.
+            {
+                return END_OF_STREAM;
+            }
+
+            byte[]  bytes = new byte[length];
+    
+            readFully(bytes);
+    
+            return buildObject(tag, bytes);
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/BERNull.java b/libcore/security/src/main/java/org/bouncycastle/asn1/BERNull.java
new file mode 100644
index 0000000..697dd4b
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/BERNull.java
@@ -0,0 +1,35 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * A BER NULL object.
+ */
+public class BERNull
+    extends DERNull
+{
+    // BEGIN android-added
+    /** non-null; unique instance of this class */
+    static public final BERNull THE_ONE = new BERNull();
+    // END android-added
+
+    // BEGIN android-changed
+    private BERNull()
+    {
+    }
+    // END android-changed
+
+    void encode(
+        DEROutputStream  out)
+        throws IOException
+    {
+        if (out instanceof ASN1OutputStream || out instanceof BEROutputStream)
+        {
+            out.write(NULL);
+        }
+        else
+        {
+            super.encode(out);
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/BEROutputStream.java b/libcore/security/src/main/java/org/bouncycastle/asn1/BEROutputStream.java
new file mode 100644
index 0000000..c2e8da4
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/BEROutputStream.java
@@ -0,0 +1,36 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class BEROutputStream
+    extends DEROutputStream
+{
+    public BEROutputStream(
+        OutputStream    os)
+    {
+        super(os);
+    }
+
+    public void writeObject(
+        Object    obj)
+        throws IOException
+    {
+        if (obj == null)
+        {
+            writeNull();
+        }
+        else if (obj instanceof DERObject)
+        {
+            ((DERObject)obj).encode(this);
+        }
+        else if (obj instanceof DEREncodable)
+        {
+            ((DEREncodable)obj).getDERObject().encode(this);
+        }
+        else
+        {
+            throw new IOException("object not BEREncodable");
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/BERSequence.java b/libcore/security/src/main/java/org/bouncycastle/asn1/BERSequence.java
new file mode 100644
index 0000000..c389fa8
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/BERSequence.java
@@ -0,0 +1,59 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+public class BERSequence
+    extends DERSequence
+{
+    /**
+     * create an empty sequence
+     */
+    public BERSequence()
+    {
+    }
+
+    /**
+     * create a sequence containing one object
+     */
+    public BERSequence(
+        DEREncodable    obj)
+    {
+        super(obj);
+    }
+
+    /**
+     * create a sequence containing a vector of objects.
+     */
+    public BERSequence(
+        DEREncodableVector   v)
+    {
+        super(v);
+    }
+
+    /*
+     */
+    void encode(
+        DEROutputStream out)
+        throws IOException
+    {
+        if (out instanceof ASN1OutputStream || out instanceof BEROutputStream)
+        {
+            out.write(SEQUENCE | CONSTRUCTED);
+            out.write(0x80);
+            
+            Enumeration e = getObjects();
+            while (e.hasMoreElements())
+            {
+                out.writeObject(e.nextElement());
+            }
+        
+            out.write(0x00);
+            out.write(0x00);
+        }
+        else
+        {
+            super.encode(out);
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/BERSet.java b/libcore/security/src/main/java/org/bouncycastle/asn1/BERSet.java
new file mode 100644
index 0000000..1ccf0fd
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/BERSet.java
@@ -0,0 +1,69 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+public class BERSet
+    extends DERSet
+{
+    /**
+     * create an empty sequence
+     */
+    public BERSet()
+    {
+    }
+
+    /**
+     * create a set containing one object
+     */
+    public BERSet(
+        DEREncodable    obj)
+    {
+        super(obj);
+    }
+
+    /**
+     * @param v - a vector of objects making up the set.
+     */
+    public BERSet(
+        DEREncodableVector   v)
+    {
+        super(v, false);
+    }
+
+    /**
+     * @param v - a vector of objects making up the set.
+     */
+    BERSet(
+        DEREncodableVector   v,
+        boolean              needsSorting)
+    {
+        super(v, needsSorting);
+    }
+
+    /*
+     */
+    void encode(
+        DEROutputStream out)
+        throws IOException
+    {
+        if (out instanceof ASN1OutputStream || out instanceof BEROutputStream)
+        {
+            out.write(SET | CONSTRUCTED);
+            out.write(0x80);
+            
+            Enumeration e = getObjects();
+            while (e.hasMoreElements())
+            {
+                out.writeObject(e.nextElement());
+            }
+        
+            out.write(0x00);
+            out.write(0x00);
+        }
+        else
+        {
+            super.encode(out);
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/BERTaggedObject.java b/libcore/security/src/main/java/org/bouncycastle/asn1/BERTaggedObject.java
new file mode 100644
index 0000000..2e06c40
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/BERTaggedObject.java
@@ -0,0 +1,119 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ * BER TaggedObject - in ASN.1 nottation this is any object proceeded by
+ * a [n] where n is some number - these are assume to follow the construction
+ * rules (as with sequences).
+ */
+public class BERTaggedObject
+    extends DERTaggedObject
+{
+    /**
+     * @param tagNo the tag number for this object.
+     * @param obj the tagged object.
+     */
+    public BERTaggedObject(
+        int             tagNo,
+        DEREncodable    obj)
+    {
+        super(tagNo, obj);
+    }
+
+    /**
+     * @param explicit true if an explicitly tagged object.
+     * @param tagNo the tag number for this object.
+     * @param obj the tagged object.
+     */
+    public BERTaggedObject(
+        boolean         explicit,
+        int             tagNo,
+        DEREncodable    obj)
+    {
+        super(explicit, tagNo, obj);
+    }
+
+    /**
+     * create an implicitly tagged object that contains a zero
+     * length sequence.
+     */
+    public BERTaggedObject(
+        int             tagNo)
+    {
+        super(false, tagNo, new BERSequence());
+    }
+
+    void encode(
+        DEROutputStream  out)
+        throws IOException
+    {
+        if (out instanceof ASN1OutputStream || out instanceof BEROutputStream)
+        {
+            out.write(CONSTRUCTED | TAGGED | tagNo);
+            out.write(0x80);
+
+            if (!empty)
+            {
+                if (!explicit)
+                {
+                    if (obj instanceof ASN1OctetString)
+                    {
+                        Enumeration  e;
+
+                        if (obj instanceof BERConstructedOctetString)
+                        {
+                            e = ((BERConstructedOctetString)obj).getObjects();
+                        }
+                        else
+                        {
+                            ASN1OctetString             octs = (ASN1OctetString)obj;
+                            BERConstructedOctetString   berO = new BERConstructedOctetString(octs.getOctets());
+
+                            e = berO.getObjects();
+                        }
+
+                        while (e.hasMoreElements())
+                        {
+                            out.writeObject(e.nextElement());
+                        }
+                    }
+                    else if (obj instanceof ASN1Sequence)
+                    {
+                        Enumeration  e = ((ASN1Sequence)obj).getObjects();
+
+                        while (e.hasMoreElements())
+                        {
+                            out.writeObject(e.nextElement());
+                        }
+                    }
+                    else if (obj instanceof ASN1Set)
+                    {
+                        Enumeration  e = ((ASN1Set)obj).getObjects();
+
+                        while (e.hasMoreElements())
+                        {
+                            out.writeObject(e.nextElement());
+                        }
+                    }
+                    else
+                    {
+                        throw new RuntimeException("not implemented: " + obj.getClass().getName());
+                    }
+                }
+                else
+                {
+                    out.writeObject(obj);
+                }
+            }
+
+            out.write(0x00);
+            out.write(0x00);
+        }
+        else
+        {
+            super.encode(out);
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERApplicationSpecific.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERApplicationSpecific.java
new file mode 100644
index 0000000..ad4f9ed
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERApplicationSpecific.java
@@ -0,0 +1,110 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * Base class for an application specific object
+ */
+public class DERApplicationSpecific 
+    extends DERObject
+{
+    private int       tag;
+    private byte[]    octets;
+    
+    public DERApplicationSpecific(
+        int        tag,
+        byte[]    octets)
+    {
+        this.tag = tag;
+        this.octets = octets;
+    }
+    
+    public DERApplicationSpecific(
+        int                  tag, 
+        DEREncodable         object) 
+        throws IOException 
+    {
+        this.tag = tag | DERTags.CONSTRUCTED;
+        
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        DEROutputStream dos = new DEROutputStream(baos);
+        
+        dos.writeObject(object);
+        
+        this.octets = baos.toByteArray();
+    }
+    
+    public boolean isConstructed()
+    {
+        return (tag & DERTags.CONSTRUCTED) != 0;
+    }
+    
+    public byte[] getContents()
+    {
+        return octets;
+    }
+    
+    public int getApplicationTag() 
+    {
+        return tag & 0x1F;
+    }
+     
+    public DERObject getObject() 
+        throws IOException 
+    {
+        return new ASN1InputStream(getContents()).readObject();
+    }
+    
+    /* (non-Javadoc)
+     * @see org.bouncycastle.asn1.DERObject#encode(org.bouncycastle.asn1.DEROutputStream)
+     */
+    void encode(DEROutputStream out) throws IOException
+    {
+        out.writeEncoded(DERTags.APPLICATION | tag, octets);
+    }
+    
+    public boolean equals(
+            Object o)
+    {
+        if ((o == null) || !(o instanceof DERApplicationSpecific))
+        {
+            return false;
+        }
+        
+        DERApplicationSpecific other = (DERApplicationSpecific)o;
+        
+        if (tag != other.tag)
+        {
+            return false;
+        }
+        
+        if (octets.length != other.octets.length)
+        {
+            return false;
+        }
+        
+        for (int i = 0; i < octets.length; i++) 
+        {
+            if (octets[i] != other.octets[i])
+            {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+    
+    public int hashCode()
+    {
+        byte[]  b = this.getContents();
+        int     value = 0;
+
+        for (int i = 0; i != b.length; i++)
+        {
+            value ^= (b[i] & 0xff) << (i % 4);
+        }
+
+        return value ^ this.getApplicationTag();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERBMPString.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERBMPString.java
new file mode 100644
index 0000000..77ed252
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERBMPString.java
@@ -0,0 +1,121 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * DER BMPString object.
+ */
+public class DERBMPString
+    extends DERObject
+    implements DERString
+{
+    String  string;
+
+    /**
+     * return a BMP String from the given object.
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static DERBMPString getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DERBMPString)
+        {
+            return (DERBMPString)obj;
+        }
+
+        if (obj instanceof ASN1OctetString)
+        {
+            return new DERBMPString(((ASN1OctetString)obj).getOctets());
+        }
+
+        if (obj instanceof ASN1TaggedObject)
+        {
+            return getInstance(((ASN1TaggedObject)obj).getObject());
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * return a BMP String from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *              be converted.
+     */
+    public static DERBMPString getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject());
+    }
+    
+
+    /**
+     * basic constructor - byte encoded string.
+     */
+    public DERBMPString(
+        byte[]   string)
+    {
+        char[]  cs = new char[string.length / 2];
+
+        for (int i = 0; i != cs.length; i++)
+        {
+            cs[i] = (char)((string[2 * i] << 8) | (string[2 * i + 1] & 0xff));
+        }
+
+        this.string = new String(cs);
+    }
+
+    /**
+     * basic constructor
+     */
+    public DERBMPString(
+        String   string)
+    {
+        this.string = string;
+    }
+
+    public String getString()
+    {
+        return string;
+    }
+
+    public int hashCode()
+    {
+        return this.getString().hashCode();
+    }
+
+    public boolean equals(
+        Object  o)
+    {
+        if (!(o instanceof DERBMPString))
+        {
+            return false;
+        }
+
+        DERBMPString  s = (DERBMPString)o;
+
+        return this.getString().equals(s.getString());
+    }
+
+    void encode(
+        DEROutputStream  out)
+        throws IOException
+    {
+        char[]  c = string.toCharArray();
+        byte[]  b = new byte[c.length * 2];
+
+        for (int i = 0; i != c.length; i++)
+        {
+            b[2 * i] = (byte)(c[i] >> 8);
+            b[2 * i + 1] = (byte)c[i];
+        }
+
+        out.writeEncoded(BMP_STRING, b);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERBitString.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERBitString.java
new file mode 100644
index 0000000..367a297
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERBitString.java
@@ -0,0 +1,289 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public class DERBitString
+    extends DERObject
+    implements DERString
+{
+    private static final char[]  table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+    
+    protected byte[]      data;
+    protected int         padBits;
+
+    /**
+     * return the correct number of pad bits for a bit string defined in
+     * a 32 bit constant
+     */
+    static protected int getPadBits(
+        int bitString)
+    {
+        int val = 0;
+        for (int i = 3; i >= 0; i--) 
+        {
+            //
+            // this may look a little odd, but if it isn't done like this pre jdk1.2
+            // JVM's break!
+            //
+            if (i != 0)
+            {
+                if ((bitString >> (i * 8)) != 0) 
+                {
+                    val = (bitString >> (i * 8)) & 0xFF;
+                    break;
+                }
+            }
+            else
+            {
+                if (bitString != 0)
+                {
+                    val = bitString & 0xFF;
+                    break;
+                }
+            }
+        }
+ 
+        if (val == 0)
+        {
+            return 7;
+        }
+
+
+        int bits = 1;
+
+        while (((val <<= 1) & 0xFF) != 0)
+        {
+            bits++;
+        }
+
+        return 8 - bits;
+    }
+
+    /**
+     * return the correct number of bytes for a bit string defined in
+     * a 32 bit constant
+     */
+    static protected byte[] getBytes(int bitString)
+    {
+        int bytes = 4;
+        for (int i = 3; i >= 1; i--)
+        {
+            if ((bitString & (0xFF << (i * 8))) != 0)
+            {
+                break;
+            }
+            bytes--;
+        }
+        
+        byte[] result = new byte[bytes];
+        for (int i = 0; i < bytes; i++)
+        {
+            result[i] = (byte) ((bitString >> (i * 8)) & 0xFF);
+        }
+
+        return result;
+    }
+
+    /**
+     * return a Bit String from the passed in object
+     *
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static DERBitString getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DERBitString)
+        {
+            return (DERBitString)obj;
+        }
+
+        if (obj instanceof ASN1OctetString)
+        {
+            byte[]  bytes = ((ASN1OctetString)obj).getOctets();
+            int     padBits = bytes[0];
+            byte[]  data = new byte[bytes.length - 1];
+
+            System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
+
+            return new DERBitString(data, padBits);
+        }
+
+        if (obj instanceof ASN1TaggedObject)
+        {
+            return getInstance(((ASN1TaggedObject)obj).getObject());
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * return a Bit String from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     */
+    public static DERBitString getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject());
+    }
+    
+    protected DERBitString(
+        byte    data,
+        int     padBits)
+    {
+        this.data = new byte[1];
+        this.data[0] = data;
+        this.padBits = padBits;
+    }
+
+    /**
+     * @param data the octets making up the bit string.
+     * @param padBits the number of extra bits at the end of the string.
+     */
+    public DERBitString(
+        byte[]  data,
+        int     padBits)
+    {
+        this.data = data;
+        this.padBits = padBits;
+    }
+
+    public DERBitString(
+        byte[]  data)
+    {
+        this(data, 0);
+    }
+
+    public DERBitString(
+        DEREncodable  obj)
+    {
+        try
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DEROutputStream         dOut = new DEROutputStream(bOut);
+
+            dOut.writeObject(obj);
+            dOut.close();
+
+            this.data = bOut.toByteArray();
+            this.padBits = 0;
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("Error processing object : " + e.toString());
+        }
+    }
+
+    public byte[] getBytes()
+    {
+        return data;
+    }
+
+    public int getPadBits()
+    {
+        return padBits;
+    }
+
+
+    /**
+     * @return the value of the bit string as an int (truncating if necessary)
+     */
+    public int intValue()
+    {
+        int value = 0;
+        
+        for (int i = 0; i != data.length && i != 4; i++)
+        {
+            value |= (data[i] & 0xff) << (8 * i);
+        }
+        
+        return value;
+    }
+    
+    void encode(
+        DEROutputStream  out)
+        throws IOException
+    {
+        byte[]  bytes = new byte[getBytes().length + 1];
+
+        bytes[0] = (byte)getPadBits();
+        System.arraycopy(getBytes(), 0, bytes, 1, bytes.length - 1);
+
+        out.writeEncoded(BIT_STRING, bytes);
+    }
+
+    public int hashCode()
+    {
+        int     value = 0;
+
+        for (int i = 0; i != data.length; i++)
+        {
+            value ^= (data[i] & 0xff) << (i % 4);
+        }
+
+        return value;
+    }
+    
+    public boolean equals(
+        Object  o)
+    {
+        if (!(o instanceof DERBitString))
+        {
+            return false;
+        }
+
+        DERBitString  other = (DERBitString)o;
+
+        if (data.length != other.data.length)
+        {
+            return false;
+        }
+
+        for (int i = 0; i != data.length; i++)
+        {
+            if (data[i] != other.data[i])
+            {
+                return false;
+            }
+        }
+
+        return (padBits == other.padBits);
+    }
+
+    public String getString()
+    {
+        StringBuffer          buf = new StringBuffer("#");
+        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+        ASN1OutputStream      aOut = new ASN1OutputStream(bOut);
+        
+        try
+        {
+            aOut.writeObject(this);
+        }
+        catch (IOException e)
+        {
+           throw new RuntimeException("internal error encoding BitString");
+        }
+        
+        byte[]    string = bOut.toByteArray();
+        
+        for (int i = 0; i != string.length; i++)
+        {
+            buf.append(table[(string[i] >>> 4) % 0xf]);
+            buf.append(table[string[i] & 0xf]);
+        }
+        
+        return buf.toString();
+    }
+
+    public String toString()
+    {
+        return getString();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERBoolean.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERBoolean.java
new file mode 100644
index 0000000..2aa93f1
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERBoolean.java
@@ -0,0 +1,132 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+public class DERBoolean
+    extends DERObject
+{
+    // BEGIN android-changed
+    private final byte  value;
+    // END android-changed
+
+    public static final DERBoolean FALSE = new DERBoolean(false);
+    public static final DERBoolean TRUE  = new DERBoolean(true);
+
+    /**
+     * return a boolean from the passed in object.
+     *
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static DERBoolean getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DERBoolean)
+        {
+            return (DERBoolean)obj;
+        }
+
+        if (obj instanceof ASN1OctetString)
+        {
+            // BEGIN android-changed
+            return getInstance(((ASN1OctetString)obj).getOctets());
+            // END android-changed
+        }
+
+        if (obj instanceof ASN1TaggedObject)
+        {
+            return getInstance(((ASN1TaggedObject)obj).getObject());
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * return a DERBoolean from the passed in boolean.
+     */
+    public static DERBoolean getInstance(
+        boolean  value)
+    {
+        return (value ? TRUE : FALSE);
+    }
+
+    // BEGIN android-added
+    /**
+     * return a DERBoolean from the passed in array.
+     */
+    public static DERBoolean getInstance(
+        byte[] octets)
+    {
+        return (octets[0] != 0) ? TRUE : FALSE;
+    }
+    // END android-added
+
+    /**
+     * return a Boolean from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     */
+    public static DERBoolean getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject());
+    }
+
+    // BEGIN android-removed
+    //private DERBoolean(
+    //    byte[]       value)
+    //{
+    //    this.value = value[0];
+    //}
+    // END android-removed
+
+    // BEGIN android-changed
+    private DERBoolean(
+        boolean     value)
+    {
+        this.value = (value) ? (byte)0xff : (byte)0;
+    }
+    // END android-changed
+
+    public boolean isTrue()
+    {
+        return (value != 0);
+    }
+
+    void encode(
+        DEROutputStream out)
+        throws IOException
+    {
+        byte[]  bytes = new byte[1];
+
+        bytes[0] = value;
+
+        out.writeEncoded(BOOLEAN, bytes);
+    }
+    
+    public boolean equals(
+        Object  o)
+    {
+        if ((o == null) || !(o instanceof DERBoolean))
+        {
+            return false;
+        }
+
+        return (value == ((DERBoolean)o).value);
+    }
+    
+    public int hashCode()
+    {
+        return value;
+    }
+
+
+    public String toString()
+    {
+      return (value != 0) ? "TRUE" : "FALSE";
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERConstructedSequence.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERConstructedSequence.java
new file mode 100644
index 0000000..99a493e
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERConstructedSequence.java
@@ -0,0 +1,53 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ * @deprecated use DERSequence.
+ */
+public class DERConstructedSequence
+    extends ASN1Sequence
+{
+    public void addObject(
+        DEREncodable obj)
+    {
+        super.addObject(obj);
+    }
+
+    public int getSize()
+    {
+        return size();
+    }
+
+    /*
+     * A note on the implementation:
+     * <p>
+     * As DER requires the constructed, definite-length model to
+     * be used for structured types, this varies slightly from the
+     * ASN.1 descriptions given. Rather than just outputing SEQUENCE,
+     * we also have to specify CONSTRUCTED, and the objects length.
+     */
+    void encode(
+        DEROutputStream out)
+        throws IOException
+    {
+        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+        DEROutputStream         dOut = new DEROutputStream(bOut);
+        Enumeration             e = this.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            Object    obj = e.nextElement();
+
+            dOut.writeObject(obj);
+        }
+
+        dOut.close();
+
+        byte[]  bytes = bOut.toByteArray();
+
+        out.writeEncoded(SEQUENCE | CONSTRUCTED, bytes);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERConstructedSet.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERConstructedSet.java
new file mode 100644
index 0000000..695cef3
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERConstructedSet.java
@@ -0,0 +1,79 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ * 
+ * @deprecated use DERSet
+ */
+public class DERConstructedSet
+    extends ASN1Set
+{
+    public DERConstructedSet()
+    {
+    }
+
+    /**
+     * @param obj - a single object that makes up the set.
+     */
+    public DERConstructedSet(
+        DEREncodable   obj)
+    {
+        this.addObject(obj);
+    }
+
+    /**
+     * @param v - a vector of objects making up the set.
+     */
+    public DERConstructedSet(
+        DEREncodableVector   v)
+    {
+        for (int i = 0; i != v.size(); i++)
+        {
+            this.addObject(v.get(i));
+        }
+    }
+
+    public void addObject(
+        DEREncodable    obj)
+    {
+        super.addObject(obj);
+    }
+
+    public int getSize()
+    {
+        return size();
+    }
+
+    /*
+     * A note on the implementation:
+     * <p>
+     * As DER requires the constructed, definite-length model to
+     * be used for structured types, this varies slightly from the
+     * ASN.1 descriptions given. Rather than just outputing SET,
+     * we also have to specify CONSTRUCTED, and the objects length.
+     */
+    void encode(
+        DEROutputStream out)
+        throws IOException
+    {
+        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+        DEROutputStream         dOut = new DEROutputStream(bOut);
+        Enumeration             e = this.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            Object    obj = e.nextElement();
+
+            dOut.writeObject(obj);
+        }
+
+        dOut.close();
+
+        byte[]  bytes = bOut.toByteArray();
+
+        out.writeEncoded(SET | CONSTRUCTED, bytes);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DEREncodable.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DEREncodable.java
new file mode 100644
index 0000000..d89305a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DEREncodable.java
@@ -0,0 +1,6 @@
+package org.bouncycastle.asn1;
+
+public interface DEREncodable
+{
+    public DERObject getDERObject();
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DEREncodableVector.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DEREncodableVector.java
new file mode 100644
index 0000000..49f3a17
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DEREncodableVector.java
@@ -0,0 +1,30 @@
+package org.bouncycastle.asn1;
+
+import java.util.Vector;
+
+/**
+ * a general class for building up a vector of DER encodable objects -
+ * this will eventually be superceded by ASN1EncodableVector so you should
+ * use that class in preference.
+ */
+public class DEREncodableVector
+{
+    private Vector  v = new Vector();
+
+    public void add(
+        DEREncodable   obj)
+    {
+        v.addElement(obj);
+    }
+
+    public DEREncodable get(
+        int i)
+    {
+        return (DEREncodable)v.elementAt(i);
+    }
+
+    public int size()
+    {
+        return v.size();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DEREnumerated.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DEREnumerated.java
new file mode 100644
index 0000000..170fd97
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DEREnumerated.java
@@ -0,0 +1,113 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+public class DEREnumerated
+    extends DERObject
+{
+    byte[]      bytes;
+
+    /**
+     * return an integer from the passed in object
+     *
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static DEREnumerated getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DEREnumerated)
+        {
+            return (DEREnumerated)obj;
+        }
+
+        if (obj instanceof ASN1OctetString)
+        {
+            return new DEREnumerated(((ASN1OctetString)obj).getOctets());
+        }
+
+        if (obj instanceof ASN1TaggedObject)
+        {
+            return getInstance(((ASN1TaggedObject)obj).getObject());
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * return an Enumerated from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     */
+    public static DEREnumerated getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject());
+    }
+
+    public DEREnumerated(
+        int         value)
+    {
+        bytes = BigInteger.valueOf(value).toByteArray();
+    }
+
+    public DEREnumerated(
+        BigInteger   value)
+    {
+        bytes = value.toByteArray();
+    }
+
+    public DEREnumerated(
+        byte[]   bytes)
+    {
+        this.bytes = bytes;
+    }
+
+    public BigInteger getValue()
+    {
+        return new BigInteger(bytes);
+    }
+
+    void encode(
+        DEROutputStream out)
+        throws IOException
+    {
+        out.writeEncoded(ENUMERATED, bytes);
+    }
+    
+    public boolean equals(
+        Object  o)
+    {
+        if (!(o instanceof DEREnumerated))
+        {
+            return false;
+        }
+
+        DEREnumerated other = (DEREnumerated)o;
+
+        if (bytes.length != other.bytes.length)
+        {
+            return false;
+        }
+
+        for (int i = 0; i != bytes.length; i++)
+        {
+            if (bytes[i] != other.bytes[i])
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+    
+    public int hashCode()
+    {
+        return this.getValue().hashCode();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERGeneralString.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERGeneralString.java
new file mode 100644
index 0000000..c93fe96
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERGeneralString.java
@@ -0,0 +1,87 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+public class DERGeneralString 
+    extends DERObject implements DERString
+{
+    private String string;
+
+    public static DERGeneralString getInstance(
+        Object obj) 
+    {
+        if (obj == null || obj instanceof DERGeneralString) 
+        {
+            return (DERGeneralString) obj;
+        }
+        if (obj instanceof ASN1OctetString) 
+        {
+            return new DERGeneralString(((ASN1OctetString) obj).getOctets());
+        }
+        if (obj instanceof ASN1TaggedObject) 
+        {
+            return getInstance(((ASN1TaggedObject) obj).getObject());
+        }
+        throw new IllegalArgumentException("illegal object in getInstance: "
+                + obj.getClass().getName());
+    }
+
+    public static DERGeneralString getInstance(
+        ASN1TaggedObject obj, 
+        boolean explicit) 
+    {
+        return getInstance(obj.getObject());
+    }
+
+    public DERGeneralString(byte[] string) 
+    {
+        char[] cs = new char[string.length];
+        for (int i = 0; i != cs.length; i++)
+        {
+            cs[i] = (char)(string[i] & 0xff);
+        }
+        this.string = new String(cs);
+    }
+
+    public DERGeneralString(String string) 
+    {
+        this.string = string;
+    }
+    
+    public String getString() 
+    {
+        return string;
+    }
+    
+    public byte[] getOctets() 
+    {
+        char[] cs = string.toCharArray();
+        byte[] bs = new byte[cs.length];
+        for (int i = 0; i != cs.length; i++) 
+        {
+            bs[i] = (byte) cs[i];
+        }
+        return bs;
+    }
+    
+    void encode(DEROutputStream out) 
+        throws IOException 
+    {
+        out.writeEncoded(GENERAL_STRING, this.getOctets());
+    }
+    
+    public int hashCode() 
+    {
+        return this.getString().hashCode();
+    }
+    
+    public boolean equals(Object o) 
+    {
+        if (!(o instanceof DERGeneralString)) 
+        {
+            return false;
+        }
+        DERGeneralString s = (DERGeneralString) o;
+        return this.getString().equals(s.getString());
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java
new file mode 100644
index 0000000..c70574b
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java
@@ -0,0 +1,202 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.SimpleTimeZone;
+
+/**
+ * Generalized time object.
+ */
+public class DERGeneralizedTime
+    extends DERObject
+{
+    String      time;
+
+    /**
+     * return a generalized time from the passed in object
+     *
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static DERGeneralizedTime getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DERGeneralizedTime)
+        {
+            return (DERGeneralizedTime)obj;
+        }
+
+        if (obj instanceof ASN1OctetString)
+        {
+            return new DERGeneralizedTime(((ASN1OctetString)obj).getOctets());
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * return a Generalized Time object from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     */
+    public static DERGeneralizedTime getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject());
+    }
+    
+    /**
+     * The correct format for this is YYYYMMDDHHMMSSZ, or without the Z
+     * for local time, or Z+-HHMM on the end, for difference between local
+     * time and UTC time.
+     * <p>
+     *
+     * @param time the time string.
+     */
+    public DERGeneralizedTime(
+        String  time)
+    {
+        this.time = time;
+    }
+
+    /**
+     * base constructer from a java.util.date object
+     */
+    public DERGeneralizedTime(
+        Date time)
+    {
+        SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'");
+
+        dateF.setTimeZone(new SimpleTimeZone(0,"Z"));
+
+        this.time = dateF.format(time);
+    }
+
+    DERGeneralizedTime(
+        byte[]  bytes)
+    {
+        //
+        // explicitly convert to characters
+        //
+        char[]  dateC = new char[bytes.length];
+
+        for (int i = 0; i != dateC.length; i++)
+        {
+            dateC[i] = (char)(bytes[i] & 0xff);
+        }
+
+        this.time = new String(dateC);
+    }
+
+    /**
+     * return the time - always in the form of 
+     *  YYYYMMDDhhmmssGMT(+hh:mm|-hh:mm).
+     * <p>
+     * Normally in a certificate we would expect "Z" rather than "GMT",
+     * however adding the "GMT" means we can just use:
+     * <pre>
+     *     dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
+     * </pre>
+     * To read in the time and get a date which is compatible with our local
+     * time zone.
+     */
+    public String getTime()
+    {
+        //
+        // standardise the format.
+        //             
+        if (time.charAt(time.length() - 1) == 'Z')
+        {
+            return time.substring(0, time.length() - 1) + "GMT+00:00";
+        }
+        else
+        {
+            int signPos = time.length() - 5;
+            char sign = time.charAt(signPos);
+            if (sign == '-' || sign == '+')
+            {
+                return time.substring(0, signPos)
+                    + "GMT"
+                    + time.substring(signPos, signPos + 3)
+                    + ":"
+                    + time.substring(signPos + 3);
+            }
+            else
+            {
+                signPos = time.length() - 3;
+                sign = time.charAt(signPos);
+                if (sign == '-' || sign == '+')
+                {
+                    return time.substring(0, signPos)
+                        + "GMT"
+                        + time.substring(signPos)
+                        + ":00";
+                }
+            }
+        }            
+
+        return time;
+    }
+
+    public Date getDate() 
+        throws ParseException
+    {
+        SimpleDateFormat dateF;
+
+        if (time.indexOf('.') == 14)
+        {
+            dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS'Z'");
+        }
+        else
+        {
+            dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'");
+        }
+        
+        dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
+        
+        return dateF.parse(time);
+    }
+    
+    private byte[] getOctets()
+    {
+        char[]  cs = time.toCharArray();
+        byte[]  bs = new byte[cs.length];
+
+        for (int i = 0; i != cs.length; i++)
+        {
+            bs[i] = (byte)cs[i];
+        }
+
+        return bs;
+    }
+
+
+    void encode(
+        DEROutputStream  out)
+        throws IOException
+    {
+        out.writeEncoded(GENERALIZED_TIME, this.getOctets());
+    }
+    
+    public boolean equals(
+        Object  o)
+    {
+        if ((o == null) || !(o instanceof DERGeneralizedTime))
+        {
+            return false;
+        }
+
+        return time.equals(((DERGeneralizedTime)o).time);
+    }
+    
+    public int hashCode()
+    {
+        return time.hashCode();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERIA5String.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERIA5String.java
new file mode 100644
index 0000000..a75ab1e
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERIA5String.java
@@ -0,0 +1,123 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * DER IA5String object - this is an ascii string.
+ */
+public class DERIA5String
+    extends DERObject
+    implements DERString
+{
+    String  string;
+
+    /**
+     * return a IA5 string from the passed in object
+     *
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static DERIA5String getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DERIA5String)
+        {
+            return (DERIA5String)obj;
+        }
+
+        if (obj instanceof ASN1OctetString)
+        {
+            return new DERIA5String(((ASN1OctetString)obj).getOctets());
+        }
+
+        if (obj instanceof ASN1TaggedObject)
+        {
+            return getInstance(((ASN1TaggedObject)obj).getObject());
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * return an IA5 String from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     */
+    public static DERIA5String getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject());
+    }
+
+    /**
+     * basic constructor - with bytes.
+     */
+    public DERIA5String(
+        byte[]   string)
+    {
+        char[]  cs = new char[string.length];
+
+        for (int i = 0; i != cs.length; i++)
+        {
+            cs[i] = (char)(string[i] & 0xff);
+        }
+
+        this.string = new String(cs);
+    }
+
+    /**
+     * basic constructor - with string.
+     */
+    public DERIA5String(
+        String   string)
+    {
+        this.string = string;
+    }
+
+    public String getString()
+    {
+        return string;
+    }
+
+    public byte[] getOctets()
+    {
+        char[]  cs = string.toCharArray();
+        byte[]  bs = new byte[cs.length];
+
+        for (int i = 0; i != cs.length; i++)
+        {
+            bs[i] = (byte)cs[i];
+        }
+
+        return bs; 
+    }
+
+    void encode(
+        DEROutputStream  out)
+        throws IOException
+    {
+        out.writeEncoded(IA5_STRING, this.getOctets());
+    }
+
+    public int hashCode()
+    {
+        return this.getString().hashCode();
+    }
+
+    public boolean equals(
+        Object  o)
+    {
+        if (!(o instanceof DERIA5String))
+        {
+            return false;
+        }
+
+        DERIA5String  s = (DERIA5String)o;
+
+        return this.getString().equals(s.getString());
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERInputStream.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERInputStream.java
new file mode 100644
index 0000000..37763e4
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERInputStream.java
@@ -0,0 +1,276 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayInputStream;
+import java.io.EOFException;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Don't use this class. It will eventually disappear, use ASN1InputStream.
+ * <br>
+ * This class is scheduled for removal.
+ * @deprecated use ASN1InputStream
+ */
+public class DERInputStream
+    extends FilterInputStream implements DERTags
+{
+    /**
+     * @deprecated use ASN1InputStream
+     */
+    public DERInputStream(
+        InputStream is)
+    {
+        super(is);
+    }
+
+    protected int readLength()
+        throws IOException
+    {
+        int length = read();
+        if (length < 0)
+        {
+            throw new IOException("EOF found when length expected");
+        }
+
+        if (length == 0x80)
+        {
+            return -1;      // indefinite-length encoding
+        }
+
+        if (length > 127)
+        {
+            int size = length & 0x7f;
+
+            if (size > 4)
+            {
+                throw new IOException("DER length more than 4 bytes");
+            }
+            
+            length = 0;
+            for (int i = 0; i < size; i++)
+            {
+                int next = read();
+
+                if (next < 0)
+                {
+                    throw new IOException("EOF found reading length");
+                }
+
+                length = (length << 8) + next;
+            }
+            
+            if (length < 0)
+            {
+                throw new IOException("corrupted steam - negative length found");
+            }
+        }
+
+        return length;
+    }
+
+    protected void readFully(
+        byte[]  bytes)
+        throws IOException
+    {
+        int     left = bytes.length;
+
+        if (left == 0)
+        {
+            return;
+        }
+
+        while (left > 0)
+        {
+            int    l = read(bytes, bytes.length - left, left);
+            
+            if (l < 0)
+            {
+                throw new EOFException("unexpected end of stream");
+            }
+            
+            left -= l;
+        }
+    }
+
+    /**
+     * build an object given its tag and a byte stream to construct it
+     * from.
+     */
+    protected DERObject buildObject(
+        int       tag,
+        byte[]    bytes)
+        throws IOException
+    {
+        switch (tag)
+        {
+        case NULL:
+            return null;   
+        case SEQUENCE | CONSTRUCTED:
+            ByteArrayInputStream    bIn = new ByteArrayInputStream(bytes);
+            BERInputStream          dIn = new BERInputStream(bIn);
+            DERConstructedSequence  seq = new DERConstructedSequence();
+
+            try
+            {
+                for (;;)
+                {
+                    DERObject   obj = dIn.readObject();
+
+                    seq.addObject(obj);
+                }
+            }
+            catch (EOFException ex)
+            {
+                return seq;
+            }
+        case SET | CONSTRUCTED:
+            bIn = new ByteArrayInputStream(bytes);
+            dIn = new BERInputStream(bIn);
+
+            ASN1EncodableVector    v = new ASN1EncodableVector();
+
+            try
+            {
+                for (;;)
+                {
+                    DERObject   obj = dIn.readObject();
+
+                    v.add(obj);
+                }
+            }
+            catch (EOFException ex)
+            {
+                return new DERConstructedSet(v);
+            }
+        case BOOLEAN:
+            // BEGIN android-changed
+            return DERBoolean.getInstance(bytes);
+            // BEGIN android-changed
+        case INTEGER:
+            return new DERInteger(bytes);
+        case ENUMERATED:
+            return new DEREnumerated(bytes);
+        case OBJECT_IDENTIFIER:
+            return new DERObjectIdentifier(bytes);
+        case BIT_STRING:
+            int     padBits = bytes[0];
+            byte[]  data = new byte[bytes.length - 1];
+
+            System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
+
+            return new DERBitString(data, padBits);
+        case UTF8_STRING:
+            return new DERUTF8String(bytes);
+        case PRINTABLE_STRING:
+            return new DERPrintableString(bytes);
+        case IA5_STRING:
+            return new DERIA5String(bytes);
+        case T61_STRING:
+            return new DERT61String(bytes);
+        case VISIBLE_STRING:
+            return new DERVisibleString(bytes);
+        case UNIVERSAL_STRING:
+            return new DERUniversalString(bytes);
+        case GENERAL_STRING:
+            return new DERGeneralString(bytes);
+        case BMP_STRING:
+            return new DERBMPString(bytes);
+        case OCTET_STRING:
+            return new DEROctetString(bytes);
+        case UTC_TIME:
+            return new DERUTCTime(bytes);
+        case GENERALIZED_TIME:
+            return new DERGeneralizedTime(bytes);
+        default:
+            //
+            // with tagged object tag number is bottom 5 bits
+            //
+            if ((tag & TAGGED) != 0)  
+            {
+                if ((tag & 0x1f) == 0x1f)
+                {
+                    throw new IOException("unsupported high tag encountered");
+                }
+
+                if (bytes.length == 0)        // empty tag!
+                {
+                    if ((tag & CONSTRUCTED) == 0)
+                    {
+                        // BEGIN android-changed
+                        return new DERTaggedObject(false, tag & 0x1f, DERNull.THE_ONE);
+                        // END android-changed
+                    }
+                    else
+                    {
+                        return new DERTaggedObject(false, tag & 0x1f, new DERConstructedSequence());
+                    }
+                }
+
+                //
+                // simple type - implicit... return an octet string
+                //
+                if ((tag & CONSTRUCTED) == 0)
+                {
+                    return new DERTaggedObject(false, tag & 0x1f, new DEROctetString(bytes));
+                }
+
+                bIn = new ByteArrayInputStream(bytes);
+                dIn = new BERInputStream(bIn);
+
+                DEREncodable dObj = dIn.readObject();
+
+                //
+                // explicitly tagged (probably!) - if it isn't we'd have to
+                // tell from the context
+                //
+                if (dIn.available() == 0)
+                {
+                    return new DERTaggedObject(tag & 0x1f, dObj);
+                }
+
+                //
+                // another implicit object, we'll create a sequence...
+                //
+                seq = new DERConstructedSequence();
+
+                seq.addObject(dObj);
+
+                try
+                {
+                    for (;;)
+                    {
+                        dObj = dIn.readObject();
+
+                        seq.addObject(dObj);
+                    }
+                }
+                catch (EOFException ex)
+                {
+                    // ignore --
+                }
+
+                return new DERTaggedObject(false, tag & 0x1f, seq);
+            }
+
+            return new DERUnknownTag(tag, bytes);
+        }
+    }
+
+    public DERObject readObject()
+        throws IOException
+    {
+        int tag = read();
+        if (tag == -1)
+        {
+            throw new EOFException();
+        }
+
+        int     length = readLength();
+        byte[]  bytes = new byte[length];
+
+        readFully(bytes);
+
+        return buildObject(tag, bytes);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERInteger.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERInteger.java
new file mode 100644
index 0000000..e80d895
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERInteger.java
@@ -0,0 +1,134 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+public class DERInteger
+    extends DERObject
+{
+    byte[]      bytes;
+
+    /**
+     * return an integer from the passed in object
+     *
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static DERInteger getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DERInteger)
+        {
+            return (DERInteger)obj;
+        }
+
+        if (obj instanceof ASN1OctetString)
+        {
+            return new DERInteger(((ASN1OctetString)obj).getOctets());
+        }
+
+        if (obj instanceof ASN1TaggedObject)
+        {
+            return getInstance(((ASN1TaggedObject)obj).getObject());
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * return an Integer from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     */
+    public static DERInteger getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject());
+    }
+
+    public DERInteger(
+        int         value)
+    {
+        bytes = BigInteger.valueOf(value).toByteArray();
+    }
+
+    public DERInteger(
+        BigInteger   value)
+    {
+        bytes = value.toByteArray();
+    }
+
+    public DERInteger(
+        byte[]   bytes)
+    {
+        this.bytes = bytes;
+    }
+
+    public BigInteger getValue()
+    {
+        return new BigInteger(bytes);
+    }
+
+    /**
+     * in some cases positive values get crammed into a space,
+     * that's not quite big enough...
+     */
+    public BigInteger getPositiveValue()
+    {
+        return new BigInteger(1, bytes);
+    }
+
+    void encode(
+        DEROutputStream out)
+        throws IOException
+    {
+        out.writeEncoded(INTEGER, bytes);
+    }
+    
+    public int hashCode()
+    {
+         int     value = 0;
+ 
+         for (int i = 0; i != bytes.length; i++)
+         {
+             value ^= (bytes[i] & 0xff) << (i % 4);
+         }
+ 
+         return value;
+    }
+
+    public boolean equals(
+        Object  o)
+    {
+        if (!(o instanceof DERInteger))
+        {
+            return false;
+        }
+
+        DERInteger other = (DERInteger)o;
+
+        if (bytes.length != other.bytes.length)
+        {
+            return false;
+        }
+
+        for (int i = 0; i != bytes.length; i++)
+        {
+            if (bytes[i] != other.bytes[i])
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public String toString()
+    {
+      return getValue().toString();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERNull.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERNull.java
new file mode 100644
index 0000000..2be5c80
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERNull.java
@@ -0,0 +1,46 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * A NULL object.
+ */
+public class DERNull
+    extends ASN1Null
+{
+    // BEGIN android-added
+    /** non-null; unique instance of this class */
+    static public final DERNull THE_ONE = new DERNull();
+    // END android-added
+
+    // BEGIN android-changed
+    private static final byte[]  zeroBytes = new byte[0];
+
+    /*package*/ DERNull()
+    {
+    }
+    // END android-changed
+
+    void encode(
+        DEROutputStream  out)
+        throws IOException
+    {
+        out.writeEncoded(NULL, zeroBytes);
+    }
+    
+    public boolean equals(
+        Object o)
+    {
+        if ((o == null) || !(o instanceof DERNull))
+        {
+            return false;
+        }
+        
+        return true;
+    }
+    
+    public int hashCode()
+    {
+        return 0;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERNumericString.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERNumericString.java
new file mode 100644
index 0000000..b53716a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERNumericString.java
@@ -0,0 +1,123 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * DER NumericString object - this is an ascii string of characters {0,1,2,3,4,5,6,7,8,9, }.
+ */
+public class DERNumericString
+    extends DERObject
+    implements DERString
+{
+    String  string;
+
+    /**
+     * return a Numeric string from the passed in object
+     *
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static DERNumericString getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DERNumericString)
+        {
+            return (DERNumericString)obj;
+        }
+
+        if (obj instanceof ASN1OctetString)
+        {
+            return new DERNumericString(((ASN1OctetString)obj).getOctets());
+        }
+
+        if (obj instanceof ASN1TaggedObject)
+        {
+            return getInstance(((ASN1TaggedObject)obj).getObject());
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * return an Numeric String from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     */
+    public static DERNumericString getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject());
+    }
+
+    /**
+     * basic constructor - with bytes.
+     */
+    public DERNumericString(
+        byte[]   string)
+    {
+        char[]  cs = new char[string.length];
+
+        for (int i = 0; i != cs.length; i++)
+        {
+            cs[i] = (char)(string[i] & 0xff);
+        }
+
+        this.string = new String(cs);
+    }
+
+    /**
+     * basic constructor - with string.
+     */
+    public DERNumericString(
+        String   string)
+    {
+        this.string = string;
+    }
+
+    public String getString()
+    {
+        return string;
+    }
+
+    public byte[] getOctets()
+    {
+        char[]  cs = string.toCharArray();
+        byte[]  bs = new byte[cs.length];
+
+        for (int i = 0; i != cs.length; i++)
+        {
+            bs[i] = (byte)cs[i];
+        }
+
+        return bs; 
+    }
+
+    void encode(
+        DEROutputStream  out)
+        throws IOException
+    {
+        out.writeEncoded(NUMERIC_STRING, this.getOctets());
+    }
+
+    public int hashCode()
+    {
+        return this.getString().hashCode();
+    }
+
+    public boolean equals(
+        Object  o)
+    {
+        if (!(o instanceof DERNumericString))
+        {
+            return false;
+        }
+
+        DERNumericString  s = (DERNumericString)o;
+
+        return this.getString().equals(s.getString());
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERObject.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERObject.java
new file mode 100644
index 0000000..42e2487
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERObject.java
@@ -0,0 +1,20 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+public abstract class DERObject
+    extends ASN1Encodable
+    implements DERTags
+{
+    public DERObject toASN1Object()
+    {
+        return this;
+    }
+    
+    public abstract int hashCode();
+    
+    public abstract boolean equals(Object o);
+    
+    abstract void encode(DEROutputStream out)
+        throws IOException;
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java
new file mode 100644
index 0000000..190d727
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java
@@ -0,0 +1,293 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigInteger;
+
+public class DERObjectIdentifier
+    extends DERObject
+{
+    String      identifier;
+
+    /**
+     * return an OID from the passed in object
+     *
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static DERObjectIdentifier getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DERObjectIdentifier)
+        {
+            return (DERObjectIdentifier)obj;
+        }
+
+        if (obj instanceof ASN1OctetString)
+        {
+            return new DERObjectIdentifier(((ASN1OctetString)obj).getOctets());
+        }
+
+        if (obj instanceof ASN1TaggedObject)
+        {
+            return getInstance(((ASN1TaggedObject)obj).getObject());
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * return an Object Identifier from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     */
+    public static DERObjectIdentifier getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject());
+    }
+    
+
+    DERObjectIdentifier(
+        byte[]  bytes)
+    {
+        StringBuffer    objId = new StringBuffer();
+        long            value = 0;
+        BigInteger      bigValue = null;
+        boolean         first = true;
+
+        for (int i = 0; i != bytes.length; i++)
+        {
+            int b = bytes[i] & 0xff;
+
+            if (value < 0x80000000000000L) 
+            {
+                value = value * 128 + (b & 0x7f);
+                if ((b & 0x80) == 0)             // end of number reached
+                {
+                    if (first)
+                    {
+                        switch ((int)value / 40)
+                        {
+                        case 0:
+                            objId.append('0');
+                            break;
+                        case 1:
+                            objId.append('1');
+                            value -= 40;
+                            break;
+                        default:
+                            objId.append('2');
+                            value -= 80;
+                        }
+                        first = false;
+                    }
+
+                    objId.append('.');
+                    objId.append(value);
+                    value = 0;
+                }
+            } 
+            else 
+            {
+                if (bigValue == null)
+                {
+                    bigValue = BigInteger.valueOf(value);
+                }
+                bigValue = bigValue.shiftLeft(7);
+                bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f));
+                if ((b & 0x80) == 0) 
+                {
+                    objId.append('.');
+                    objId.append(bigValue);
+                    bigValue = null;
+                    value = 0;
+                }
+            }
+        }
+
+        // BEGIN android-changed
+        /*
+         * Intern the identifier so there aren't hundreds of duplicates
+         * (in practice).
+         */
+        this.identifier = objId.toString().intern();
+        // END android-changed
+    }
+
+    public DERObjectIdentifier(
+        String  identifier)
+    {
+        if (!isValidIdentifier(identifier))
+        {
+            throw new IllegalArgumentException("string " + identifier + " not an OID");
+        }
+
+        // BEGIN android-changed
+        /*
+         * Intern the identifier so there aren't hundreds of duplicates
+         * (in practice).
+         */
+        this.identifier = identifier.intern();
+        // END android-changed
+    }
+
+    public String getId()
+    {
+        return identifier;
+    }
+
+    private void writeField(
+        OutputStream    out,
+        long            fieldValue)
+        throws IOException
+    {
+        if (fieldValue >= (1L << 7))
+        {
+            if (fieldValue >= (1L << 14))
+            {
+                if (fieldValue >= (1L << 21))
+                {
+                    if (fieldValue >= (1L << 28))
+                    {
+                        if (fieldValue >= (1L << 35))
+                        {
+                            if (fieldValue >= (1L << 42))
+                            {
+                                if (fieldValue >= (1L << 49))
+                                {
+                                    if (fieldValue >= (1L << 56))
+                                    {
+                                        out.write((int)(fieldValue >> 56) | 0x80);
+                                    }
+                                    out.write((int)(fieldValue >> 49) | 0x80);
+                                }
+                                out.write((int)(fieldValue >> 42) | 0x80);
+                            }
+                            out.write((int)(fieldValue >> 35) | 0x80);
+                        }
+                        out.write((int)(fieldValue >> 28) | 0x80);
+                    }
+                    out.write((int)(fieldValue >> 21) | 0x80);
+                }
+                out.write((int)(fieldValue >> 14) | 0x80);
+            }
+            out.write((int)(fieldValue >> 7) | 0x80);
+        }
+        out.write((int)fieldValue & 0x7f);
+    }
+
+    private void writeField(
+        OutputStream    out,
+        BigInteger      fieldValue)
+        throws IOException
+    {
+        int byteCount = (fieldValue.bitLength()+6)/7;
+        if (byteCount == 0) 
+        {
+            out.write(0);
+        }  
+        else 
+        {
+            BigInteger tmpValue = fieldValue;
+            byte[] tmp = new byte[byteCount];
+            for (int i = byteCount-1; i >= 0; i--) 
+            {
+                tmp[i] = (byte) ((tmpValue.intValue() & 0x7f) | 0x80);
+                tmpValue = tmpValue.shiftRight(7); 
+            }
+            tmp[byteCount-1] &= 0x7f;
+            out.write(tmp);
+        }
+
+    }
+
+    void encode(
+        DEROutputStream out)
+        throws IOException
+    {
+        OIDTokenizer            tok = new OIDTokenizer(identifier);
+        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+        DEROutputStream         dOut = new DEROutputStream(bOut);
+
+        writeField(bOut, 
+                    Integer.parseInt(tok.nextToken()) * 40
+                    + Integer.parseInt(tok.nextToken()));
+
+        while (tok.hasMoreTokens())
+        {
+            String token = tok.nextToken();
+            if (token.length() < 18) 
+            {
+                writeField(bOut, Long.parseLong(token));
+            }
+            else
+            {
+                writeField(bOut, new BigInteger(token));
+            }
+        }
+
+        dOut.close();
+
+        byte[]  bytes = bOut.toByteArray();
+
+        out.writeEncoded(OBJECT_IDENTIFIER, bytes);
+    }
+
+    public int hashCode()
+    {
+        return identifier.hashCode();
+    }
+
+    public boolean equals(
+        Object  o)
+    {
+        if ((o == null) || !(o instanceof DERObjectIdentifier))
+        {
+            return false;
+        }
+
+        return identifier.equals(((DERObjectIdentifier)o).identifier);
+    }
+
+    public String toString()
+    {
+        return getId();
+    }
+
+    private static boolean isValidIdentifier(
+        String identifier)
+    {
+        boolean periodAllowed = false;
+        for (int i = identifier.length() - 1; i >= 0; i--)
+        {
+            char ch = identifier.charAt(i);
+
+            if ('0' <= ch && ch <= '9')
+            {
+                periodAllowed = true;
+                continue;
+            }
+
+            if (ch == '.')
+            {
+                if (!periodAllowed)
+                {
+                    return false;
+                }
+
+                periodAllowed = false;
+                continue;
+            }
+
+            return false;
+        }
+
+        return periodAllowed;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DEROctetString.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DEROctetString.java
new file mode 100644
index 0000000..bf7a86b
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DEROctetString.java
@@ -0,0 +1,29 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+public class DEROctetString
+    extends ASN1OctetString
+{
+    /**
+     * @param string the octets making up the octet string.
+     */
+    public DEROctetString(
+        byte[]  string)
+    {
+        super(string);
+    }
+
+    public DEROctetString(
+        DEREncodable  obj)
+    {
+        super(obj);
+    }
+
+    void encode(
+        DEROutputStream out)
+        throws IOException
+    {
+        out.writeEncoded(OCTET_STRING, string);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DEROutputStream.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DEROutputStream.java
new file mode 100644
index 0000000..f55142c
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DEROutputStream.java
@@ -0,0 +1,81 @@
+package org.bouncycastle.asn1;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class DEROutputStream
+    extends FilterOutputStream implements DERTags
+{
+    public DEROutputStream(
+        OutputStream    os)
+    {
+        super(os);
+    }
+
+    private void writeLength(
+        int length)
+        throws IOException
+    {
+        if (length > 127)
+        {
+            int size = 1;
+            int val = length;
+
+            while ((val >>>= 8) != 0)
+            {
+                size++;
+            }
+
+            write((byte)(size | 0x80));
+
+            for (int i = (size - 1) * 8; i >= 0; i -= 8)
+            {
+                write((byte)(length >> i));
+            }
+        }
+        else
+        {
+            write((byte)length);
+        }
+    }
+
+    void writeEncoded(
+        int     tag,
+        byte[]  bytes)
+        throws IOException
+    {
+        write(tag);
+        writeLength(bytes.length);
+        write(bytes);
+    }
+
+    protected void writeNull()
+        throws IOException
+    {
+        write(NULL);
+        write(0x00);
+    }
+
+    public void writeObject(
+        Object    obj)
+        throws IOException
+    {
+        if (obj == null)
+        {
+            writeNull();
+        }
+        else if (obj instanceof DERObject)
+        {
+            ((DERObject)obj).encode(this);
+        }
+        else if (obj instanceof DEREncodable)
+        {
+            ((DEREncodable)obj).getDERObject().encode(this);
+        }
+        else 
+        {
+            throw new IOException("object not DEREncodable");
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERPrintableString.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERPrintableString.java
new file mode 100644
index 0000000..00aec9b
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERPrintableString.java
@@ -0,0 +1,134 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * DER PrintableString object.
+ */
+public class DERPrintableString
+    extends DERObject
+    implements DERString
+{
+    // BEGIN android-changed
+    private final String string;
+    // END android-changed
+
+    /**
+     * return a printable string from the passed in object.
+     * 
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static DERPrintableString getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DERPrintableString)
+        {
+            return (DERPrintableString)obj;
+        }
+
+        if (obj instanceof ASN1OctetString)
+        {
+            return new DERPrintableString(((ASN1OctetString)obj).getOctets());
+        }
+
+        if (obj instanceof ASN1TaggedObject)
+        {
+            return getInstance(((ASN1TaggedObject)obj).getObject());
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * return a Printable String from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     */
+    public static DERPrintableString getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject());
+    }
+
+    /**
+     * basic constructor - byte encoded string.
+     */
+    public DERPrintableString(
+        byte[]   string)
+    {
+        char[]  cs = new char[string.length];
+
+        for (int i = 0; i != cs.length; i++)
+        {
+            cs[i] = (char)(string[i] & 0xff);
+        }
+
+        // BEGIN android-changed
+        this.string = new String(cs).intern();
+        // END android-changed
+    }
+
+    /**
+     * basic constructor
+     */
+    public DERPrintableString(
+        String   string)
+    {
+        // BEGIN android-changed
+        this.string = string.intern();
+        // END android-changed
+    }
+
+    public String getString()
+    {
+        return string;
+    }
+
+    public byte[] getOctets()
+    {
+        char[]  cs = string.toCharArray();
+        byte[]  bs = new byte[cs.length];
+
+        for (int i = 0; i != cs.length; i++)
+        {
+            bs[i] = (byte)cs[i];
+        }
+
+        return bs; 
+    }
+
+    void encode(
+        DEROutputStream  out)
+        throws IOException
+    {
+        out.writeEncoded(PRINTABLE_STRING, this.getOctets());
+    }
+
+    public int hashCode()
+    {
+        return this.getString().hashCode();
+    }
+
+    public boolean equals(
+        Object  o)
+    {
+        if (!(o instanceof DERPrintableString))
+        {
+            return false;
+        }
+
+        DERPrintableString  s = (DERPrintableString)o;
+
+        return this.getString().equals(s.getString());
+    }
+
+    public String toString()
+    {
+      return string;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERSequence.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERSequence.java
new file mode 100644
index 0000000..1cfd38d
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERSequence.java
@@ -0,0 +1,79 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+
+public class DERSequence
+    extends ASN1Sequence
+{
+    /**
+     * create an empty sequence
+     */
+    public DERSequence()
+    {
+    }
+
+    /**
+     * create a sequence containing one object
+     */
+    public DERSequence(
+        DEREncodable    obj)
+    {
+        this.addObject(obj);
+    }
+
+    /**
+     * create a sequence containing a vector of objects.
+     */
+    public DERSequence(
+        DEREncodableVector   v)
+    {
+        for (int i = 0; i != v.size(); i++)
+        {
+            this.addObject(v.get(i));
+        }
+    }
+
+    /**
+     * create a sequence containing an array of objects.
+     */
+    public DERSequence(
+        ASN1Encodable[]   a)
+    {
+        for (int i = 0; i != a.length; i++)
+        {
+            this.addObject(a[i]);
+        }
+    }
+    
+    /*
+     * A note on the implementation:
+     * <p>
+     * As DER requires the constructed, definite-length model to
+     * be used for structured types, this varies slightly from the
+     * ASN.1 descriptions given. Rather than just outputing SEQUENCE,
+     * we also have to specify CONSTRUCTED, and the objects length.
+     */
+    void encode(
+        DEROutputStream out)
+        throws IOException
+    {
+        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+        DEROutputStream         dOut = new DEROutputStream(bOut);
+        Enumeration             e = this.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            Object    obj = e.nextElement();
+
+            dOut.writeObject(obj);
+        }
+
+        dOut.close();
+
+        byte[]  bytes = bOut.toByteArray();
+
+        out.writeEncoded(SEQUENCE | CONSTRUCTED, bytes);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERSet.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERSet.java
new file mode 100644
index 0000000..e1aa1d5
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERSet.java
@@ -0,0 +1,99 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ * A DER encoded set object
+ */
+public class DERSet
+    extends ASN1Set
+{
+    /**
+     * create an empty set
+     */
+    public DERSet()
+    {
+    }
+
+    /**
+     * @param obj - a single object that makes up the set.
+     */
+    public DERSet(
+        DEREncodable   obj)
+    {
+        this.addObject(obj);
+    }
+
+    /**
+     * @param v - a vector of objects making up the set.
+     */
+    public DERSet(
+        DEREncodableVector   v)
+    {
+        this(v, true);
+    }
+    
+    /**
+     * create a set from an array of objects.
+     */
+    public DERSet(
+        ASN1Encodable[]   a)
+    {
+        for (int i = 0; i != a.length; i++)
+        {
+            this.addObject(a[i]);
+        }
+        
+        this.sort();
+    }
+    
+    /**
+     * @param v - a vector of objects making up the set.
+     */
+    DERSet(
+        DEREncodableVector   v,
+        boolean              needsSorting)
+    {
+        for (int i = 0; i != v.size(); i++)
+        {
+            this.addObject(v.get(i));
+        }
+
+        if (needsSorting)
+        {
+            this.sort();
+        }
+    }
+
+    /*
+     * A note on the implementation:
+     * <p>
+     * As DER requires the constructed, definite-length model to
+     * be used for structured types, this varies slightly from the
+     * ASN.1 descriptions given. Rather than just outputing SET,
+     * we also have to specify CONSTRUCTED, and the objects length.
+     */
+    void encode(
+        DEROutputStream out)
+        throws IOException
+    {
+        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+        DEROutputStream         dOut = new DEROutputStream(bOut);
+        Enumeration             e = this.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            Object    obj = e.nextElement();
+
+            dOut.writeObject(obj);
+        }
+
+        dOut.close();
+
+        byte[]  bytes = bOut.toByteArray();
+
+        out.writeEncoded(SET | CONSTRUCTED, bytes);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERString.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERString.java
new file mode 100644
index 0000000..3143be9
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERString.java
@@ -0,0 +1,9 @@
+package org.bouncycastle.asn1;
+
+/**
+ * basic interface for DER string objects.
+ */
+public interface DERString
+{
+    public String getString();
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERT61String.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERT61String.java
new file mode 100644
index 0000000..8c7c99a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERT61String.java
@@ -0,0 +1,121 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * DER T61String (also the teletex string)
+ */
+public class DERT61String
+    extends DERObject
+    implements DERString
+{
+    String  string;
+
+    /**
+     * return a T61 string from the passed in object.
+     *
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static DERT61String getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DERT61String)
+        {
+            return (DERT61String)obj;
+        }
+
+        if (obj instanceof ASN1OctetString)
+        {
+            return new DERT61String(((ASN1OctetString)obj).getOctets());
+        }
+
+        if (obj instanceof ASN1TaggedObject)
+        {
+            return getInstance(((ASN1TaggedObject)obj).getObject());
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * return an T61 String from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     */
+    public static DERT61String getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject());
+    }
+
+    /**
+     * basic constructor - with bytes.
+     */
+    public DERT61String(
+        byte[]   string)
+    {
+        char[]  cs = new char[string.length];
+
+        for (int i = 0; i != cs.length; i++)
+        {
+            cs[i] = (char)(string[i] & 0xff);
+        }
+
+        this.string = new String(cs);
+    }
+
+    /**
+     * basic constructor - with string.
+     */
+    public DERT61String(
+        String   string)
+    {
+        this.string = string;
+    }
+
+    public String getString()
+    {
+        return string;
+    }
+
+    void encode(
+        DEROutputStream  out)
+        throws IOException
+    {
+        out.writeEncoded(T61_STRING, this.getOctets());
+    }
+    
+    public byte[] getOctets()
+    {
+        char[]  cs = string.toCharArray();
+        byte[]  bs = new byte[cs.length];
+
+        for (int i = 0; i != cs.length; i++)
+        {
+            bs[i] = (byte)cs[i];
+        }
+
+        return bs; 
+    }
+
+    public boolean equals(
+        Object  o)
+    {
+        if ((o == null) || !(o instanceof DERT61String))
+        {
+            return false;
+        }
+
+        return this.getString().equals(((DERT61String)o).getString());
+    }
+    
+    public int hashCode()
+    {
+        return this.getString().hashCode();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERTaggedObject.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERTaggedObject.java
new file mode 100644
index 0000000..d42f0d6
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERTaggedObject.java
@@ -0,0 +1,88 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * DER TaggedObject - in ASN.1 nottation this is any object proceeded by
+ * a [n] where n is some number - these are assume to follow the construction
+ * rules (as with sequences).
+ */
+public class DERTaggedObject
+    extends ASN1TaggedObject
+{
+    /**
+     * @param tagNo the tag number for this object.
+     * @param obj the tagged object.
+     */
+    public DERTaggedObject(
+        int             tagNo,
+        DEREncodable    obj)
+    {
+        super(tagNo, obj);
+    }
+
+    /**
+     * @param explicit true if an explicitly tagged object.
+     * @param tagNo the tag number for this object.
+     * @param obj the tagged object.
+     */
+    public DERTaggedObject(
+        boolean         explicit,
+        int             tagNo,
+        DEREncodable    obj)
+    {
+        super(explicit, tagNo, obj);
+    }
+
+    /**
+     * create an implicitly tagged object that contains a zero
+     * length sequence.
+     */
+    public DERTaggedObject(
+        int             tagNo)
+    {
+        super(false, tagNo, new DERSequence());
+    }
+
+    void encode(
+        DEROutputStream  out)
+        throws IOException
+    {
+        if (!empty)
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DEROutputStream         dOut = new DEROutputStream(bOut);
+
+            dOut.writeObject(obj);
+            dOut.close();
+
+            byte[]  bytes = bOut.toByteArray();
+
+            if (explicit)
+            {
+                out.writeEncoded(CONSTRUCTED | TAGGED | tagNo, bytes);
+            }
+            else
+            {
+                //
+                // need to mark constructed types...
+                //
+                if ((bytes[0] & CONSTRUCTED) != 0)
+                {
+                    bytes[0] = (byte)(CONSTRUCTED | TAGGED | tagNo);
+                }
+                else
+                {
+                    bytes[0] = (byte)(TAGGED | tagNo);
+                }
+
+                out.write(bytes);
+            }
+        }
+        else
+        {
+            out.writeEncoded(CONSTRUCTED | TAGGED | tagNo, new byte[0]);
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERTags.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERTags.java
new file mode 100644
index 0000000..ef441ef
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERTags.java
@@ -0,0 +1,36 @@
+package org.bouncycastle.asn1;
+
+public interface DERTags
+{
+    public static final int BOOLEAN             = 0x01;
+    public static final int INTEGER             = 0x02;
+    public static final int BIT_STRING          = 0x03;
+    public static final int OCTET_STRING        = 0x04;
+    public static final int NULL                = 0x05;
+    public static final int OBJECT_IDENTIFIER   = 0x06;
+    public static final int EXTERNAL            = 0x08;
+    public static final int ENUMERATED          = 0x0a;
+    public static final int SEQUENCE            = 0x10;
+    public static final int SEQUENCE_OF         = 0x10; // for completeness
+    public static final int SET                 = 0x11;
+    public static final int SET_OF              = 0x11; // for completeness
+
+
+    public static final int NUMERIC_STRING      = 0x12;
+    public static final int PRINTABLE_STRING    = 0x13;
+    public static final int T61_STRING          = 0x14;
+    public static final int VIDEOTEX_STRING     = 0x15;
+    public static final int IA5_STRING          = 0x16;
+    public static final int UTC_TIME            = 0x17;
+    public static final int GENERALIZED_TIME    = 0x18;
+    public static final int GRAPHIC_STRING      = 0x19;
+    public static final int VISIBLE_STRING      = 0x1a;
+    public static final int GENERAL_STRING      = 0x1b;
+    public static final int UNIVERSAL_STRING    = 0x1c;
+    public static final int BMP_STRING          = 0x1e;
+    public static final int UTF8_STRING         = 0x0c;
+    
+    public static final int CONSTRUCTED         = 0x20;
+    public static final int APPLICATION         = 0x40;
+    public static final int TAGGED              = 0x80;
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERUTCTime.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERUTCTime.java
new file mode 100644
index 0000000..a6d0cc7
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERUTCTime.java
@@ -0,0 +1,193 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.SimpleTimeZone;
+
+/**
+ * UTC time object.
+ */
+public class DERUTCTime
+    extends DERObject
+{
+    String      time;
+
+    /**
+     * return an UTC Time from the passed in object.
+     *
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static DERUTCTime getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DERUTCTime)
+        {
+            return (DERUTCTime)obj;
+        }
+
+        if (obj instanceof ASN1OctetString)
+        {
+            return new DERUTCTime(((ASN1OctetString)obj).getOctets());
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * return an UTC Time from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     */
+    public static DERUTCTime getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject());
+    }
+    
+    /**
+     * The correct format for this is YYMMDDHHMMSSZ (it used to be that seconds were
+     * never encoded. When you're creating one of these objects from scratch, that's
+     * what you want to use, otherwise we'll try to deal with whatever gets read from
+     * the input stream... (this is why the input format is different from the getTime()
+     * method output).
+     * <p>
+     *
+     * @param time the time string.
+     */
+    public DERUTCTime(
+        String  time)
+    {
+        this.time = time;
+    }
+
+    /**
+     * base constructer from a java.util.date object
+     */
+    public DERUTCTime(
+        Date time)
+    {
+        SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'");
+
+        dateF.setTimeZone(new SimpleTimeZone(0,"Z"));
+
+        this.time = dateF.format(time);
+    }
+
+    DERUTCTime(
+        byte[]  bytes)
+    {
+        //
+        // explicitly convert to characters
+        //
+        char[]  dateC = new char[bytes.length];
+
+        for (int i = 0; i != dateC.length; i++)
+        {
+            dateC[i] = (char)(bytes[i] & 0xff);
+        }
+
+        this.time = new String(dateC);
+    }
+
+    /**
+     * return the time - always in the form of 
+     *  YYMMDDhhmmssGMT(+hh:mm|-hh:mm).
+     * <p>
+     * Normally in a certificate we would expect "Z" rather than "GMT",
+     * however adding the "GMT" means we can just use:
+     * <pre>
+     *     dateF = new SimpleDateFormat("yyMMddHHmmssz");
+     * </pre>
+     * To read in the time and get a date which is compatible with our local
+     * time zone.
+     * <p>
+     * <b>Note:</b> In some cases, due to the local date processing, this
+     * may lead to unexpected results. If you want to stick the normal
+     * convention of 1950 to 2049 use the getAdjustedTime() method.
+     */
+    public String getTime()
+    {
+        //
+        // standardise the format.
+        //
+        if (time.length() == 11)
+        {
+            return time.substring(0, 10) + "00GMT+00:00";
+        }
+        else if (time.length() == 13)
+        {
+            return time.substring(0, 12) + "GMT+00:00";
+        }
+        else if (time.length() == 17)
+        {
+            return time.substring(0, 12) + "GMT" + time.substring(12, 15) + ":" + time.substring(15, 17);
+        }
+
+        return time;
+    }
+
+    /**
+     * return the time as an adjusted date with a 4 digit year. This goes
+     * in the range of 1950 - 2049.
+     */
+    public String getAdjustedTime()
+    {
+        String   d = this.getTime();
+
+        if (d.charAt(0) < '5')
+        {
+            return "20" + d;
+        }
+        else
+        {
+            return "19" + d;
+        }
+    }
+
+    private byte[] getOctets()
+    {
+        char[]  cs = time.toCharArray();
+        byte[]  bs = new byte[cs.length];
+
+        for (int i = 0; i != cs.length; i++)
+        {
+            bs[i] = (byte)cs[i];
+        }
+
+        return bs;
+    }
+
+    void encode(
+        DEROutputStream  out)
+        throws IOException
+    {
+        out.writeEncoded(UTC_TIME, this.getOctets());
+    }
+    
+    public boolean equals(
+        Object  o)
+    {
+        if ((o == null) || !(o instanceof DERUTCTime))
+        {
+            return false;
+        }
+
+        return time.equals(((DERUTCTime)o).time);
+    }
+    
+    public int hashCode()
+    {
+        return time.hashCode();
+    }
+
+    public String toString() 
+    {
+      return time;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERUTF8String.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERUTF8String.java
new file mode 100644
index 0000000..1402d38
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERUTF8String.java
@@ -0,0 +1,104 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+import org.bouncycastle.util.Strings;
+
+/**
+ * DER UTF8String object.
+ */
+public class DERUTF8String
+    extends DERObject
+    implements DERString
+{
+    String string;
+
+    /**
+     * return an UTF8 string from the passed in object.
+     * 
+     * @exception IllegalArgumentException
+     *                if the object cannot be converted.
+     */
+    public static DERUTF8String getInstance(Object obj)
+    {
+        if (obj == null || obj instanceof DERUTF8String)
+        {
+            return (DERUTF8String)obj;
+        }
+
+        if (obj instanceof ASN1OctetString)
+        {
+            return new DERUTF8String(((ASN1OctetString)obj).getOctets());
+        }
+
+        if (obj instanceof ASN1TaggedObject)
+        {
+            return getInstance(((ASN1TaggedObject)obj).getObject());
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: "
+                + obj.getClass().getName());
+    }
+
+    /**
+     * return an UTF8 String from a tagged object.
+     * 
+     * @param obj
+     *            the tagged object holding the object we want
+     * @param explicit
+     *            true if the object is meant to be explicitly tagged false
+     *            otherwise.
+     * @exception IllegalArgumentException
+     *                if the tagged object cannot be converted.
+     */
+    public static DERUTF8String getInstance(
+        ASN1TaggedObject obj,
+        boolean explicit)
+    {
+        return getInstance(obj.getObject());
+    }
+
+    /**
+     * basic constructor - byte encoded string.
+     */
+    DERUTF8String(byte[] string)
+    {
+        this.string = Strings.fromUTF8ByteArray(string);
+    }
+
+    /**
+     * basic constructor
+     */
+    public DERUTF8String(String string)
+    {
+        this.string = string;
+    }
+
+    public String getString()
+    {
+        return string;
+    }
+
+    public int hashCode()
+    {
+        return this.getString().hashCode();
+    }
+
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof DERUTF8String))
+        {
+            return false;
+        }
+
+        DERUTF8String s = (DERUTF8String)o;
+
+        return this.getString().equals(s.getString());
+    }
+
+    void encode(DEROutputStream out)
+        throws IOException
+    {
+        out.writeEncoded(UTF8_STRING, Strings.toUTF8ByteArray(string));
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERUniversalString.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERUniversalString.java
new file mode 100644
index 0000000..ec8c519
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERUniversalString.java
@@ -0,0 +1,115 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * DER UniversalString object.
+ */
+public class DERUniversalString
+    extends DERObject
+    implements DERString
+{
+    private static final char[]  table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+    private byte[] string;
+    
+    /**
+     * return a Universal String from the passed in object.
+     *
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static DERUniversalString getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DERUniversalString)
+        {
+            return (DERUniversalString)obj;
+        }
+
+        if (obj instanceof ASN1OctetString)
+        {
+            return new DERUniversalString(((ASN1OctetString)obj).getOctets());
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * return a Universal String from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     */
+    public static DERUniversalString getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject());
+    }
+
+    /**
+     * basic constructor - byte encoded string.
+     */
+    public DERUniversalString(
+        byte[]   string)
+    {
+        this.string = string;
+    }
+
+    public String getString()
+    {
+        StringBuffer    buf = new StringBuffer("#");
+        ByteArrayOutputStream    bOut = new ByteArrayOutputStream();
+        ASN1OutputStream            aOut = new ASN1OutputStream(bOut);
+        
+        try
+        {
+            aOut.writeObject(this);
+        }
+        catch (IOException e)
+        {
+           throw new RuntimeException("internal error encoding BitString");
+        }
+        
+        byte[]    string = bOut.toByteArray();
+        
+        for (int i = 0; i != string.length; i++)
+        {
+            buf.append(table[(string[i] >>> 4) % 0xf]);
+            buf.append(table[string[i] & 0xf]);
+        }
+        
+        return buf.toString();
+    }
+
+    public byte[] getOctets()
+    {
+        return string;
+    }
+
+    void encode(
+        DEROutputStream  out)
+        throws IOException
+    {
+        out.writeEncoded(UNIVERSAL_STRING, this.getOctets());
+    }
+    
+    public boolean equals(
+        Object  o)
+    {
+        if ((o == null) || !(o instanceof DERUniversalString))
+        {
+            return false;
+        }
+
+        return this.getString().equals(((DERUniversalString)o).getString());
+    }
+    
+    public int hashCode()
+    {
+        return this.getString().hashCode();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERUnknownTag.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERUnknownTag.java
new file mode 100644
index 0000000..8b0631c
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERUnknownTag.java
@@ -0,0 +1,86 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * We insert one of these when we find a tag we don't recognise.
+ */
+public class DERUnknownTag
+    extends DERObject
+{
+    int         tag;
+    byte[]      data;
+
+    /**
+     * @param tag the tag value.
+     * @param data the octets making up the time.
+     */
+    public DERUnknownTag(
+        int     tag,
+        byte[]  data)
+    {
+        this.tag = tag;
+        this.data = data;
+    }
+
+    public int getTag()
+    {
+        return tag;
+    }
+
+    public byte[] getData()
+    {
+        return data;
+    }
+
+    void encode(
+        DEROutputStream  out)
+        throws IOException
+    {
+        out.writeEncoded(tag, data);
+    }
+    
+    public boolean equals(
+        Object o)
+    {
+        if ((o == null) || !(o instanceof DERUnknownTag))
+        {
+            return false;
+        }
+        
+        DERUnknownTag other = (DERUnknownTag)o;
+        
+        if (tag != other.tag)
+        {
+            return false;
+        }
+        
+        if (data.length != other.data.length)
+        {
+            return false;
+        }
+        
+        for (int i = 0; i < data.length; i++) 
+        {
+            if(data[i] != other.data[i])
+            {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+    
+    public int hashCode()
+    {
+        byte[]  b = this.getData();
+        int     value = 0;
+
+        for (int i = 0; i != b.length; i++)
+        {
+            value ^= (b[i] & 0xff) << (i % 4);
+        }
+
+        return value ^ this.getTag();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/DERVisibleString.java b/libcore/security/src/main/java/org/bouncycastle/asn1/DERVisibleString.java
new file mode 100644
index 0000000..1660eb2
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/DERVisibleString.java
@@ -0,0 +1,121 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * DER VisibleString object.
+ */
+public class DERVisibleString
+    extends DERObject
+    implements DERString
+{
+    String  string;
+
+    /**
+     * return a Visible String from the passed in object.
+     *
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static DERVisibleString getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DERVisibleString)
+        {
+            return (DERVisibleString)obj;
+        }
+
+        if (obj instanceof ASN1OctetString)
+        {
+            return new DERVisibleString(((ASN1OctetString)obj).getOctets());
+        }
+
+        if (obj instanceof ASN1TaggedObject)
+        {
+            return getInstance(((ASN1TaggedObject)obj).getObject());
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * return a Visible String from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the tagged object cannot
+     *               be converted.
+     */
+    public static DERVisibleString getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject());
+    }
+
+    /**
+     * basic constructor - byte encoded string.
+     */
+    public DERVisibleString(
+        byte[]   string)
+    {
+        char[]  cs = new char[string.length];
+
+        for (int i = 0; i != cs.length; i++)
+        {
+            cs[i] = (char)(string[i] & 0xff);
+        }
+
+        this.string = new String(cs);
+    }
+
+    /**
+     * basic constructor
+     */
+    public DERVisibleString(
+        String   string)
+    {
+        this.string = string;
+    }
+
+    public String getString()
+    {
+        return string;
+    }
+
+    public byte[] getOctets()
+    {
+        char[]  cs = string.toCharArray();
+        byte[]  bs = new byte[cs.length];
+
+        for (int i = 0; i != cs.length; i++)
+        {
+            bs[i] = (byte)cs[i];
+        }
+
+        return bs;
+    }
+
+    void encode(
+        DEROutputStream  out)
+        throws IOException
+    {
+        out.writeEncoded(VISIBLE_STRING, this.getOctets());
+    }
+    
+    public boolean equals(
+        Object  o)
+    {
+        if ((o == null) || !(o instanceof DERVisibleString))
+        {
+            return false;
+        }
+
+        return this.getString().equals(((DERVisibleString)o).getString());
+    }
+    
+    public int hashCode()
+    {
+        return this.getString().hashCode();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/OIDTokenizer.java b/libcore/security/src/main/java/org/bouncycastle/asn1/OIDTokenizer.java
new file mode 100644
index 0000000..5467944
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/OIDTokenizer.java
@@ -0,0 +1,48 @@
+package org.bouncycastle.asn1;
+
+/**
+ * class for breaking up an OID into it's component tokens, ala
+ * java.util.StringTokenizer. We need this class as some of the
+ * lightweight Java environment don't support classes like
+ * StringTokenizer.
+ */
+public class OIDTokenizer
+{
+    private String  oid;
+    private int     index;
+
+    public OIDTokenizer(
+        String oid)
+    {
+        this.oid = oid;
+        this.index = 0;
+    }
+
+    public boolean hasMoreTokens()
+    {
+        return (index != -1);
+    }
+
+    public String nextToken()
+    {
+        if (index == -1)
+        {
+            return null;
+        }
+
+        String  token;
+        int     end = oid.indexOf('.', index);
+
+        if (end == -1)
+        {
+            token = oid.substring(index);
+            index = -1;
+            return token;
+        }
+
+        token = oid.substring(index, end);
+
+        index = end + 1;
+        return token;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/OrderedTable.java b/libcore/security/src/main/java/org/bouncycastle/asn1/OrderedTable.java
new file mode 100644
index 0000000..511aba2
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/OrderedTable.java
@@ -0,0 +1,224 @@
+package org.bouncycastle.asn1;
+
+import java.util.Enumeration;
+import java.util.ConcurrentModificationException;
+
+// BEGIN android-note
+/*
+ * This is a new class that was synthesized from the observed
+ * requirement for a lookup table that preserves order. Since in
+ * practice the element count is typically very low, we just use a
+ * flat list rather than doing any hashing / bucketing.
+ */
+// END android-note
+
+/**
+ * Ordered lookup table. Instances of this class will keep up to four
+ * key-value pairs directly, resorting to an external collection only
+ * if more elements than that need to be stored.
+ */
+public final class OrderedTable {
+    /** null-ok; key #0 */
+    private DERObjectIdentifier key0;
+    
+    /** null-ok; key #1 */
+    private DERObjectIdentifier key1;
+
+    /** null-ok; key #2 */
+    private DERObjectIdentifier key2;
+
+    /** null-ok; key #3 */
+    private DERObjectIdentifier key3;
+    
+    /** null-ok; value #0 */
+    private Object value0;
+    
+    /** null-ok; value #1 */
+    private Object value1;
+
+    /** null-ok; value #2 */
+    private Object value2;
+
+    /** null-ok; value #3 */
+    private Object value3;
+    
+    /**
+     * null-ok; array of additional keys and values, alternating
+     * key then value, etc. 
+     */
+    private Object[] rest;
+
+    /** &gt;= 0; number of elements in the list */
+    private int size;
+
+    // Note: Default public constructor.
+
+    /**
+     * Adds an element.
+     * 
+     * @param key non-null; the key
+     * @param value non-null; the value
+     */
+    public void add(DERObjectIdentifier key, Object value) {
+        if (key == null) {
+            throw new NullPointerException("key == null");
+        }
+
+        if (value == null) {
+            throw new NullPointerException("value == null");
+        }
+
+        int sz = size;
+
+        switch (sz) {
+            case 0: {
+                key0 = key;
+                value0 = value;
+                break;
+            }
+            case 1: {
+                key1 = key;
+                value1 = value;
+                break;
+            }
+            case 2: {
+                key2 = key;
+                value2 = value;
+                break;
+            }
+            case 3: {
+                key3 = key;
+                value3 = value;
+                break;
+            }
+            case 4: {
+                // Do initial allocation of rest.
+                rest = new Object[10];
+                rest[0] = key;
+                rest[1] = value;
+                break;
+            }
+            default: {
+                int index = (sz - 4) * 2;
+                int index1 = index + 1;
+                if (index1 >= rest.length) {
+                    // Grow rest.
+                    Object[] newRest = new Object[index1 * 2 + 10];
+                    System.arraycopy(rest, 0, newRest, 0, rest.length);
+                    rest = newRest;
+                }
+                rest[index] = key;
+                rest[index1] = value;
+                break;
+            }
+        }
+        
+        size = sz + 1;
+    }
+
+    /**
+     * Gets the number of elements in this instance.
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Look up the given key, returning the associated value if found.
+     * 
+     * @param key non-null; the key to look up
+     * @return null-ok; the associated value
+     */
+    public Object get(DERObjectIdentifier key) {
+        int keyHash = key.hashCode();
+        int sz = size;
+
+        for (int i = 0; i < size; i++) {
+            DERObjectIdentifier probe = getKey(i);
+            if ((probe.hashCode() == keyHash) &&
+                    probe.equals(key)) {
+                return getValue(i);
+            }
+        }
+
+        return null;
+    }
+    
+    /**
+     * Gets the nth key.
+     * 
+     * @param n index
+     * @return non-null; the nth key
+     */
+    public DERObjectIdentifier getKey(int n) {
+        if ((n < 0) || (n >= size)) {
+            throw new IndexOutOfBoundsException(Integer.toString(n));
+        }
+
+        switch (n) {
+            case 0: return key0;
+            case 1: return key1;
+            case 2: return key2;
+            case 3: return key3;
+            default: return (DERObjectIdentifier) rest[(n - 4) * 2];
+        }
+    }
+
+    /**
+     * Gets the nth value.
+     * 
+     * @param n index
+     * @return non-null; the nth value
+     */
+    public Object getValue(int n) {
+        if ((n < 0) || (n >= size)) {
+            throw new IndexOutOfBoundsException(Integer.toString(n));
+        }
+
+        switch (n) {
+            case 0: return value0;
+            case 1: return value1;
+            case 2: return value2;
+            case 3: return value3;
+            default: return rest[((n - 4) * 2) + 1];
+        }
+    }
+
+    /**
+     * Gets an enumeration of the keys, in order.
+     * 
+     * @return non-null; an enumeration of the keys
+     */
+    public Enumeration getKeys() {
+        return new KeyEnumeration();
+    }
+
+    /**
+     * Associated enumeration class.
+     */
+    private class KeyEnumeration implements Enumeration {
+        /** original size; used for modification detection */
+        private final int origSize = size;
+
+        /** &gt;= 0; current cursor */
+        private int at = 0;
+
+        /** {@inheritDoc} */
+        public boolean hasMoreElements() {
+            if (size != origSize) {
+                throw new ConcurrentModificationException();
+            }
+
+            return at < origSize;
+        }
+
+        /** {@inheritDoc} */
+        public Object nextElement() {
+            if (size != origSize) {
+                throw new ConcurrentModificationException();
+            }
+
+            return getKey(at++);
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cmp/PKIFailureInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cmp/PKIFailureInfo.java
new file mode 100644
index 0000000..5d97e0a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cmp/PKIFailureInfo.java
@@ -0,0 +1,104 @@
+package org.bouncycastle.asn1.cmp;
+
+import org.bouncycastle.asn1.DERBitString;
+
+/**
+ * <pre>
+ * PKIFailureInfo ::= BIT STRING {
+ * badAlg               (0),
+ *   -- unrecognized or unsupported Algorithm Identifier
+ * badMessageCheck      (1), -- integrity check failed (e.g., signature did not verify)
+ * badRequest           (2),
+ *   -- transaction not permitted or supported
+ * badTime              (3), -- messageTime was not sufficiently close to the system time, as defined by local policy
+ * badCertId            (4), -- no certificate could be found matching the provided criteria
+ * badDataFormat        (5),
+ *   -- the data submitted has the wrong format
+ * wrongAuthority       (6), -- the authority indicated in the request is different from the one creating the response token
+ * incorrectData        (7), -- the requester's data is incorrect (for notary services)
+ * missingTimeStamp     (8), -- when the timestamp is missing but should be there (by policy)
+ * badPOP               (9)  -- the proof-of-possession failed
+ * timeNotAvailable    (14),
+ *   -- the TSA's time source is not available
+ * unacceptedPolicy    (15),
+ *   -- the requested TSA policy is not supported by the TSA
+ * unacceptedExtension (16),
+ *   -- the requested extension is not supported by the TSA
+ *  addInfoNotAvailable (17)
+ *    -- the additional information requested could not be understood
+ *    -- or is not available
+ *  systemFailure       (25)
+ *    -- the request cannot be handled due to system failure 
+ * </pre>
+ */
+public class PKIFailureInfo
+    extends DERBitString
+{
+
+
+    public static final int badAlg               = (1 << 7); // unrecognized or unsupported Algorithm Identifier
+    public static final int badMessageCheck      = (1 << 6); // integrity check failed (e.g., signature did not verify)
+    public static final int badRequest           = (1 << 5);
+    public static final int badTime              = (1 << 4); // -- messageTime was not sufficiently close to the system time, as defined by local policy
+    public static final int badCertId            = (1 << 3); // no certificate could be found matching the provided criteria
+    public static final int badDataFormat        = (1 << 2);
+    public static final int wrongAuthority       = (1 << 1); // the authority indicated in the request is different from the one creating the response token
+    public static final int incorrectData        = 1;        // the requester's data is incorrect (for notary services)
+    public static final int missingTimeStamp     = (1 << 15); // when the timestamp is missing but should be there (by policy)
+    public static final int badPOP               = (1 << 14); // the proof-of-possession failed
+    public static final int timeNotAvailable     = (1 << 9); // the TSA's time source is not available
+    public static final int unacceptedPolicy     = (1 << 8); // the requested TSA policy is not supported by the TSA
+    public static final int unacceptedExtension  = (1 << 23); //the requested extension is not supported by the TSA
+    public static final int addInfoNotAvailable  = (1 << 22); //the additional information requested could not be understood or is not available
+    public static final int systemFailure        = (1 << 30); //the request cannot be handled due to system failure
+    
+    /** @deprecated use lower case version */
+    public static final int BAD_ALG                   = badAlg; // unrecognized or unsupported Algorithm Identifier
+    /** @deprecated use lower case version */
+    public static final int BAD_MESSAGE_CHECK         = badMessageCheck;
+    /** @deprecated use lower case version */
+    public static final int BAD_REQUEST               = badRequest; // transaction not permitted or supported
+    /** @deprecated use lower case version */
+    public static final int BAD_TIME                  = badTime;
+    /** @deprecated use lower case version */
+    public static final int BAD_CERT_ID               = badCertId;
+    /** @deprecated use lower case version */
+    public static final int BAD_DATA_FORMAT           = badDataFormat; // the data submitted has the wrong format
+    /** @deprecated use lower case version */
+    public static final int WRONG_AUTHORITY           = wrongAuthority;
+    /** @deprecated use lower case version */
+    public static final int INCORRECT_DATA            = incorrectData;
+    /** @deprecated use lower case version */
+    public static final int MISSING_TIME_STAMP        = missingTimeStamp;
+    /** @deprecated use lower case version */
+    public static final int BAD_POP                   = badPOP;
+    /** @deprecated use lower case version */
+    public static final int TIME_NOT_AVAILABLE        = timeNotAvailable;
+    /** @deprecated use lower case version */
+    public static final int UNACCEPTED_POLICY         = unacceptedPolicy;
+    /** @deprecated use lower case version */
+    public static final int UNACCEPTED_EXTENSION      = unacceptedExtension;
+    /** @deprecated use lower case version */
+    public static final int ADD_INFO_NOT_AVAILABLE    = addInfoNotAvailable; 
+    /** @deprecated use lower case version */
+    public static final int SYSTEM_FAILURE            = systemFailure; 
+    /**
+     * Basic constructor.
+     */
+    public PKIFailureInfo(
+        int info)
+    {
+        super(getBytes(info), getPadBits(info));
+    }
+
+    public PKIFailureInfo(
+        DERBitString info)
+    {
+        super(info.getBytes(), info.getPadBits());
+    }
+    
+    public String toString()
+    {
+        return "PKIFailureInfo: 0x" + Integer.toHexString(this.intValue());
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cmp/PKIFreeText.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cmp/PKIFreeText.java
new file mode 100644
index 0000000..f821071
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cmp/PKIFreeText.java
@@ -0,0 +1,91 @@
+package org.bouncycastle.asn1.cmp;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERUTF8String;
+
+public class PKIFreeText
+    extends ASN1Encodable
+{
+    ASN1Sequence strings;
+
+    public static PKIFreeText getInstance(
+        ASN1TaggedObject    obj,
+        boolean             explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static PKIFreeText getInstance(
+        Object obj)
+    {
+        if (obj instanceof PKIFreeText)
+        {
+            return (PKIFreeText)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new PKIFreeText((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("Unknown object in factory");
+    }
+
+    public PKIFreeText(
+        ASN1Sequence seq)
+    {
+        Enumeration e = seq.getObjects();
+        while (e.hasMoreElements())
+        {
+            if (!(e.nextElement() instanceof DERUTF8String))
+            {
+                throw new IllegalArgumentException("attempt to insert non UTF8 STRING into PKIFreeText");
+            }
+        }
+        
+        strings = seq;
+    }
+
+    public PKIFreeText(
+        DERUTF8String p)
+    {
+        strings = new DERSequence(p);
+    }
+
+    /**
+     * Return the number of string elements present.
+     * 
+     * @return number of elements present.
+     */
+    public int size()
+    {
+        return strings.size();
+    }
+    
+    /**
+     * Return the UTF8STRING at index i.
+     * 
+     * @param i index of the string of interest
+     * @return the string at index i.
+     */
+    public DERUTF8String getStringAt(
+        int i)
+    {
+        return (DERUTF8String)strings.getObjectAt(i);
+    }
+    
+    /**
+     * <pre>
+     * PKIFreeText ::= SEQUENCE SIZE (1..MAX) OF UTF8String
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        return strings;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cmp/PKIStatus.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cmp/PKIStatus.java
new file mode 100644
index 0000000..58b2b69
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cmp/PKIStatus.java
@@ -0,0 +1,13 @@
+package org.bouncycastle.asn1.cmp;
+
+public interface PKIStatus
+{
+
+  public static final int GRANTED                 = 0;
+  public static final int GRANTED_WITH_MODS       = 1;
+  public static final int REJECTION               = 2;
+  public static final int WAITING                 = 3;
+  public static final int REVOCATION_WARNING      = 4;
+  public static final int REVOCATION_NOTIFICATION = 5;
+
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cmp/PKIStatusInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cmp/PKIStatusInfo.java
new file mode 100644
index 0000000..b4f37cc
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cmp/PKIStatusInfo.java
@@ -0,0 +1,164 @@
+package org.bouncycastle.asn1.cmp;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+public class PKIStatusInfo
+    extends ASN1Encodable
+{
+    DERInteger      status;
+    PKIFreeText     statusString;
+    DERBitString    failInfo;
+
+    public static PKIStatusInfo getInstance(
+        ASN1TaggedObject obj,
+        boolean explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static PKIStatusInfo getInstance(
+        Object obj)
+    {
+        if (obj instanceof PKIStatusInfo)
+        {
+            return (PKIStatusInfo)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new PKIStatusInfo((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass());
+    }
+
+    public PKIStatusInfo(
+        ASN1Sequence seq)
+    {
+        this.status = DERInteger.getInstance(seq.getObjectAt(0));
+
+        this.statusString = null;
+        this.failInfo = null;
+
+        if (seq.size() > 2)
+        {
+            this.statusString = PKIFreeText.getInstance(seq.getObjectAt(1));
+            this.failInfo = DERBitString.getInstance(seq.getObjectAt(2));
+        }
+        else if (seq.size() > 1)
+        {
+            Object obj = seq.getObjectAt(1); 
+            if (obj instanceof DERBitString)
+            {
+                this.failInfo = DERBitString.getInstance(obj);
+            }
+            else
+            {
+                this.statusString = PKIFreeText.getInstance(obj);
+            }
+        }
+    }
+
+    /**
+     * @param status
+     */
+    public PKIStatusInfo(int status)
+    {
+        this.status = new DERInteger(status);
+    }
+
+    /**
+     * @param status
+     * @param statusString
+     */
+    public PKIStatusInfo(
+        int         status,
+        PKIFreeText statusString)
+    {
+        this.status = new DERInteger(status);
+        this.statusString = statusString;
+    }
+
+    public PKIStatusInfo(
+            int            status,
+            PKIFreeText    statusString,
+            PKIFailureInfo failInfo)
+    {
+        this.status = new DERInteger(status);
+        this.statusString = statusString;
+        this.failInfo = failInfo;
+    }
+    
+    public BigInteger getStatus()
+    {
+        return status.getValue();
+    }
+
+    public PKIFreeText getStatusString()
+    {
+        return statusString;
+    }
+
+    public DERBitString getFailInfo()
+    {
+        return failInfo;
+    }
+
+    /**
+     * <pre>
+     * PKIStatusInfo ::= SEQUENCE {
+     *     status        PKIStatus,                (INTEGER)
+     *     statusString  PKIFreeText     OPTIONAL,
+     *     failInfo      PKIFailureInfo  OPTIONAL  (BIT STRING)
+     * }
+     *
+     * PKIStatus:
+     *   granted                (0), -- you got exactly what you asked for
+     *   grantedWithMods        (1), -- you got something like what you asked for
+     *   rejection              (2), -- you don't get it, more information elsewhere in the message
+     *   waiting                (3), -- the request body part has not yet been processed, expect to hear more later
+     *   revocationWarning      (4), -- this message contains a warning that a revocation is imminent
+     *   revocationNotification (5), -- notification that a revocation has occurred
+     *   keyUpdateWarning       (6)  -- update already done for the oldCertId specified in CertReqMsg
+     *
+     * PKIFailureInfo:
+     *   badAlg           (0), -- unrecognized or unsupported Algorithm Identifier
+     *   badMessageCheck  (1), -- integrity check failed (e.g., signature did not verify)
+     *   badRequest       (2), -- transaction not permitted or supported
+     *   badTime          (3), -- messageTime was not sufficiently close to the system time, as defined by local policy
+     *   badCertId        (4), -- no certificate could be found matching the provided criteria
+     *   badDataFormat    (5), -- the data submitted has the wrong format
+     *   wrongAuthority   (6), -- the authority indicated in the request is different from the one creating the response token
+     *   incorrectData    (7), -- the requester's data is incorrect (for notary services)
+     *   missingTimeStamp (8), -- when the timestamp is missing but should be there (by policy)
+     *   badPOP           (9)  -- the proof-of-possession failed
+     *
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(status);
+
+        if (statusString != null)
+        {
+            v.add(statusString);
+        }
+
+        if (failInfo!= null)
+        {
+            v.add(failInfo);
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/Attribute.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/Attribute.java
new file mode 100644
index 0000000..dbec62e
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/Attribute.java
@@ -0,0 +1,82 @@
+package org.bouncycastle.asn1.cms;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+
+public class Attribute
+    extends ASN1Encodable
+{
+    private DERObjectIdentifier attrType;
+    private ASN1Set             attrValues;
+
+    /**
+     * return an Attribute object from the given object.
+     *
+     * @param o the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static Attribute getInstance(
+        Object o)
+    {
+        if (o == null || o instanceof Attribute)
+        {
+            return (Attribute)o;
+        }
+        
+        if (o instanceof ASN1Sequence)
+        {
+            return new Attribute((ASN1Sequence)o);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+    
+    public Attribute(
+        ASN1Sequence seq)
+    {
+        attrType = (DERObjectIdentifier)seq.getObjectAt(0);
+        attrValues = (ASN1Set)seq.getObjectAt(1);
+    }
+
+    public Attribute(
+        DERObjectIdentifier attrType,
+        ASN1Set             attrValues)
+    {
+        this.attrType = attrType;
+        this.attrValues = attrValues;
+    }
+
+    public DERObjectIdentifier getAttrType()
+    {
+        return attrType;
+    }
+    
+    public ASN1Set getAttrValues()
+    {
+        return attrValues;
+    }
+
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * Attribute ::= SEQUENCE {
+     *     attrType OBJECT IDENTIFIER,
+     *     attrValues SET OF AttributeValue
+     * }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(attrType);
+        v.add(attrValues);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java
new file mode 100644
index 0000000..9b4d79f
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java
@@ -0,0 +1,173 @@
+package org.bouncycastle.asn1.cms;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.DEREncodableVector;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+public class AttributeTable
+{
+    private Hashtable attributes = new Hashtable();
+
+    public AttributeTable(
+        Hashtable  attrs)
+    {
+        attributes = copyTable(attrs);
+    }
+
+    public AttributeTable(
+        DEREncodableVector v)
+    {
+        for (int i = 0; i != v.size(); i++)
+        {
+            Attribute   a = Attribute.getInstance(v.get(i));
+
+            addAttribute(a.getAttrType(), a);
+        }
+    }
+
+    public AttributeTable(
+        ASN1Set    s)
+    {
+        for (int i = 0; i != s.size(); i++)
+        {
+            Attribute   a = Attribute.getInstance(s.getObjectAt(i));
+
+            addAttribute(a.getAttrType(), a);
+        }
+    }
+
+    private void addAttribute(
+        DERObjectIdentifier oid,
+        Attribute           a)
+    {
+        Object value = attributes.get(oid);
+        
+        if (value == null)
+        {
+            attributes.put(oid, a);
+        }
+        else
+        {
+            Vector v;
+            
+            if (value instanceof Attribute)
+            {
+                v = new Vector();
+                
+                v.addElement(value);
+                v.addElement(a);
+            }
+            else
+            {
+                v = (Vector)value;
+            
+                v.addElement(a);
+            }
+            
+            attributes.put(oid, v);
+        }
+    }
+    
+    /**
+     * Return the first attribute matching the OBJECT IDENTIFIER oid.
+     * 
+     * @param oid type of attribute required.
+     * @return first attribute found of type oid.
+     */
+    public Attribute get(
+        DERObjectIdentifier oid)
+    {
+        Object value = attributes.get(oid);
+        
+        if (value instanceof Vector)
+        {
+            return (Attribute)((Vector)value).elementAt(0);
+        }
+        
+        return (Attribute)value;
+    }
+
+    /**
+     * Return all the attributes matching the OBJECT IDENTIFIER oid. The vector will be 
+     * empty if there are no attributes of the required type present.
+     * 
+     * @param oid type of attribute required.
+     * @return a vector of all the attributes found of type oid.
+     */
+    public ASN1EncodableVector getAll(
+        DERObjectIdentifier oid)
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+        
+        Object value = attributes.get(oid);
+        
+        if (value instanceof Vector)
+        {
+            Enumeration e = ((Vector)value).elements();
+            
+            while (e.hasMoreElements())
+            {
+                v.add((Attribute)e.nextElement());
+            }
+        }
+        else if (value != null)
+        {
+            v.add((Attribute)value);
+        }
+        
+        return v;
+    }
+    
+    public Hashtable toHashtable()
+    {
+        return copyTable(attributes);
+    }
+    
+    public ASN1EncodableVector toASN1EncodableVector()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+        Enumeration          e = attributes.elements();
+        
+        while (e.hasMoreElements())
+        {
+            Object value = e.nextElement();
+            
+            if (value instanceof Vector)
+            {
+                Enumeration en = ((Vector)value).elements();
+                
+                while (en.hasMoreElements())
+                {
+                    v.add(Attribute.getInstance(en.nextElement()));
+                }
+            }
+            else
+            {
+                v.add(Attribute.getInstance(value));
+            }
+        }
+        
+        return v;
+    }
+    
+    private Hashtable copyTable(
+        Hashtable in)
+    {
+        Hashtable   out = new Hashtable();
+        Enumeration e = in.keys();
+        
+        while (e.hasMoreElements())
+        {
+            Object key = e.nextElement();
+            
+            out.put(key, in.get(key));
+        }
+        
+        return out;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java
new file mode 100644
index 0000000..bdcca6a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java
@@ -0,0 +1,12 @@
+package org.bouncycastle.asn1.cms;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+
+public interface CMSAttributes
+{
+    public static final DERObjectIdentifier  contentType = PKCSObjectIdentifiers.pkcs_9_at_contentType;
+    public static final DERObjectIdentifier  messageDigest = PKCSObjectIdentifiers.pkcs_9_at_messageDigest;
+    public static final DERObjectIdentifier  signingTime = PKCSObjectIdentifiers.pkcs_9_at_signingTime;
+    public static final DERObjectIdentifier  counterSignature = PKCSObjectIdentifiers.pkcs_9_at_counterSignature;
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java
new file mode 100644
index 0000000..2e6b312
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java
@@ -0,0 +1,15 @@
+package org.bouncycastle.asn1.cms;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+
+public interface CMSObjectIdentifiers
+{
+    static final DERObjectIdentifier    data = PKCSObjectIdentifiers.data;
+    static final DERObjectIdentifier    signedData = PKCSObjectIdentifiers.signedData;
+    static final DERObjectIdentifier    envelopedData = PKCSObjectIdentifiers.envelopedData;
+    static final DERObjectIdentifier    signedAndEnvelopedData = PKCSObjectIdentifiers.signedAndEnvelopedData;
+    static final DERObjectIdentifier    digestedData = PKCSObjectIdentifiers.digestedData;
+    static final DERObjectIdentifier    encryptedData = PKCSObjectIdentifiers.encryptedData;
+    static final DERObjectIdentifier    compressedData = PKCSObjectIdentifiers.id_ct_compressedData;
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/CompressedData.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/CompressedData.java
new file mode 100644
index 0000000..2331059
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/CompressedData.java
@@ -0,0 +1,110 @@
+package org.bouncycastle.asn1.cms;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.BERSequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/** 
+ * RFC 3274 - CMS Compressed Data.
+ * <pre>
+ * CompressedData ::= SEQUENCE {
+ *  version CMSVersion,
+ *  compressionAlgorithm CompressionAlgorithmIdentifier,
+ *  encapContentInfo EncapsulatedContentInfo
+ * }
+ * </pre>
+ */
+public class CompressedData
+    extends ASN1Encodable
+{
+    private DERInteger           version;
+    private AlgorithmIdentifier  compressionAlgorithm;
+    private ContentInfo          encapContentInfo;
+
+    public CompressedData(
+        AlgorithmIdentifier compressionAlgorithm,
+        ContentInfo         encapContentInfo)
+    {
+        this.version = new DERInteger(0);
+        this.compressionAlgorithm = compressionAlgorithm;
+        this.encapContentInfo = encapContentInfo;
+    }
+    
+    public CompressedData(
+        ASN1Sequence seq)
+    {
+        this.version = (DERInteger)seq.getObjectAt(0);
+        this.compressionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
+        this.encapContentInfo = ContentInfo.getInstance(seq.getObjectAt(2));
+
+    }
+
+    /**
+     * return a CompressedData object from a tagged object.
+     *
+     * @param _ato the tagged object holding the object we want.
+     * @param _explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the object held by the
+     *          tagged object cannot be converted.
+     */
+    public static CompressedData getInstance(
+        ASN1TaggedObject _ato,
+        boolean _explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(_ato, _explicit));
+    }
+    
+    /**
+     * return a CompressedData object from the given object.
+     *
+     * @param _obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static CompressedData getInstance(
+        Object _obj)
+    {
+        if (_obj == null || _obj instanceof CompressedData)
+        {
+            return (CompressedData)_obj;
+        }
+        
+        if (_obj instanceof ASN1Sequence)
+        {
+            return new CompressedData((ASN1Sequence)_obj);
+        }
+        
+        throw new IllegalArgumentException("Invalid CompressedData: " + _obj.getClass().getName());
+    }
+
+    public DERInteger getVersion()
+    {
+        return version;
+    }
+
+    public AlgorithmIdentifier getCompressionAlgorithmIdentifier()
+    {
+        return compressionAlgorithm;
+    }
+
+    public ContentInfo getEncapContentInfo()
+    {
+        return encapContentInfo;
+    }
+
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(version);
+        v.add(compressionAlgorithm);
+        v.add(encapContentInfo);
+
+        return new BERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java
new file mode 100644
index 0000000..76801a3
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java
@@ -0,0 +1,90 @@
+package org.bouncycastle.asn1.cms;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.BERSequence;
+import org.bouncycastle.asn1.BERTaggedObject;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+public class ContentInfo
+    extends ASN1Encodable
+    implements CMSObjectIdentifiers
+{
+    private DERObjectIdentifier contentType;
+    private DEREncodable        content;
+
+    public static ContentInfo getInstance(
+        Object  obj)
+    {
+        if (obj instanceof ContentInfo)
+        {
+            return (ContentInfo)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new ContentInfo((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+    }
+
+    public ContentInfo(
+        ASN1Sequence  seq)
+    {
+        Enumeration   e = seq.getObjects();
+
+        contentType = (DERObjectIdentifier)e.nextElement();
+
+        if (e.hasMoreElements())
+        {
+            content = ((ASN1TaggedObject)e.nextElement()).getObject();
+        }
+    }
+
+    public ContentInfo(
+        DERObjectIdentifier contentType,
+        DEREncodable        content)
+    {
+        this.contentType = contentType;
+        this.content = content;
+    }
+
+    public DERObjectIdentifier getContentType()
+    {
+        return contentType;
+    }
+
+    public DEREncodable getContent()
+    {
+        return content;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * ContentInfo ::= SEQUENCE {
+     *          contentType ContentType,
+     *          content
+     *          [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(contentType);
+
+        if (content != null)
+        {
+            v.add(new BERTaggedObject(0, content));
+        }
+
+        return new BERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/EncryptedContentInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/EncryptedContentInfo.java
new file mode 100644
index 0000000..22ac839
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/EncryptedContentInfo.java
@@ -0,0 +1,106 @@
+package org.bouncycastle.asn1.cms;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.BERSequence;
+import org.bouncycastle.asn1.BERTaggedObject;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class EncryptedContentInfo
+    extends ASN1Encodable
+{
+    private DERObjectIdentifier contentType;
+    private AlgorithmIdentifier contentEncryptionAlgorithm;
+    private ASN1OctetString     encryptedContent;
+    
+    public EncryptedContentInfo(
+        DERObjectIdentifier contentType, 
+        AlgorithmIdentifier contentEncryptionAlgorithm,
+        ASN1OctetString     encryptedContent)
+    {
+        this.contentType = contentType;
+        this.contentEncryptionAlgorithm = contentEncryptionAlgorithm;
+        this.encryptedContent = encryptedContent;
+    }
+    
+    public EncryptedContentInfo(
+        ASN1Sequence seq)
+    {
+        contentType = (DERObjectIdentifier)seq.getObjectAt(0);
+        contentEncryptionAlgorithm = AlgorithmIdentifier.getInstance(
+                                                        seq.getObjectAt(1));
+        if (seq.size() > 2)
+        {
+            encryptedContent = ASN1OctetString.getInstance(
+                                (ASN1TaggedObject)seq.getObjectAt(2), false);
+        }
+    }
+
+    /**
+     * return an EncryptedContentInfo object from the given object.
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static EncryptedContentInfo getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof EncryptedContentInfo)
+        {
+            return (EncryptedContentInfo)obj;
+        }
+        
+        if (obj instanceof ASN1Sequence)
+        {
+            return new EncryptedContentInfo((ASN1Sequence)obj);
+        }
+        
+        throw new IllegalArgumentException("Invalid EncryptedContentInfo: "
+                                                + obj.getClass().getName());
+    }
+
+    public DERObjectIdentifier getContentType()
+    {
+        return contentType;
+    }
+
+    public AlgorithmIdentifier getContentEncryptionAlgorithm()
+    {
+        return contentEncryptionAlgorithm;
+    }
+
+    public ASN1OctetString getEncryptedContent()
+    {
+        return encryptedContent;
+    }
+
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * EncryptedContentInfo ::= SEQUENCE {
+     *     contentType ContentType,
+     *     contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+     *     encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL 
+     * }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+        
+        v.add(contentType);
+        v.add(contentEncryptionAlgorithm);
+
+        if (encryptedContent != null)
+        {
+            v.add(new BERTaggedObject(false, 0, encryptedContent));
+        }
+        
+        return new BERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/EnvelopedData.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/EnvelopedData.java
new file mode 100644
index 0000000..f4ac42c
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/EnvelopedData.java
@@ -0,0 +1,179 @@
+package org.bouncycastle.asn1.cms;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.BERSequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+public class EnvelopedData
+    extends ASN1Encodable
+{
+    private DERInteger              version;
+    private OriginatorInfo          originatorInfo;
+    private ASN1Set                 recipientInfos;
+    private EncryptedContentInfo    encryptedContentInfo;
+    private ASN1Set                 unprotectedAttrs;
+
+    public EnvelopedData(
+        OriginatorInfo          originatorInfo,
+        ASN1Set                 recipientInfos,
+        EncryptedContentInfo    encryptedContentInfo,
+        ASN1Set                 unprotectedAttrs)
+    {
+        if (originatorInfo != null || unprotectedAttrs != null)
+        {
+            version = new DERInteger(2);
+        }
+        else
+        {
+            version = new DERInteger(0);
+
+            Enumeration e = recipientInfos.getObjects();
+
+            while (e.hasMoreElements())
+            {
+                RecipientInfo   ri = RecipientInfo.getInstance(e.nextElement());
+
+                if (!ri.getVersion().equals(version))
+                {
+                    version = new DERInteger(2);
+                    break;
+                }
+            }
+        }
+
+        this.originatorInfo = originatorInfo;
+        this.recipientInfos = recipientInfos;
+        this.encryptedContentInfo = encryptedContentInfo;
+        this.unprotectedAttrs = unprotectedAttrs;
+    }
+                         
+    public EnvelopedData(
+        ASN1Sequence seq)
+    {
+        int     index = 0;
+        
+        version = (DERInteger)seq.getObjectAt(index++);
+        
+        Object  tmp = seq.getObjectAt(index++);
+
+        if (tmp instanceof ASN1TaggedObject)
+        {
+            originatorInfo = OriginatorInfo.getInstance((ASN1TaggedObject)tmp, false);
+            tmp = seq.getObjectAt(index++);
+        }
+
+        recipientInfos = ASN1Set.getInstance(tmp);
+        
+        encryptedContentInfo = EncryptedContentInfo.getInstance(seq.getObjectAt(index++));
+        
+        if(seq.size() > index)
+        {
+            unprotectedAttrs = ASN1Set.getInstance((ASN1TaggedObject)seq.getObjectAt(index), false);
+        }
+    }
+    
+    /**
+     * return an EnvelopedData object from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want.
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the object held by the
+     *          tagged object cannot be converted.
+     */
+    public static EnvelopedData getInstance(
+        ASN1TaggedObject obj,
+        boolean explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+    
+    /**
+     * return an EnvelopedData object from the given object.
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static EnvelopedData getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof EnvelopedData)
+        {
+            return (EnvelopedData)obj;
+        }
+        
+        if (obj instanceof ASN1Sequence)
+        {
+            return new EnvelopedData((ASN1Sequence)obj);
+        }
+        
+        throw new IllegalArgumentException("Invalid EnvelopedData: " + obj.getClass().getName());
+    }
+
+    public DERInteger getVersion()
+    {
+        return version;
+    }
+    
+    public OriginatorInfo getOriginatorInfo()
+    {
+        return originatorInfo;
+    }
+
+    public ASN1Set getRecipientInfos()
+    {
+        return recipientInfos;
+    }
+
+    public EncryptedContentInfo getEncryptedContentInfo()
+    {
+        return encryptedContentInfo;
+    }
+
+    public ASN1Set getUnprotectedAttrs()
+    {
+        return unprotectedAttrs;
+    }
+
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * EnvelopedData ::= SEQUENCE {
+     *     version CMSVersion,
+     *     originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+     *     recipientInfos RecipientInfos,
+     *     encryptedContentInfo EncryptedContentInfo,
+     *     unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL 
+     * }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+        
+        v.add(version);
+
+        if (originatorInfo != null)
+        {
+            v.add(new DERTaggedObject(false, 0, originatorInfo));
+        }
+
+        v.add(recipientInfos);
+        v.add(encryptedContentInfo);
+
+        if (unprotectedAttrs != null)
+        {
+            v.add(new DERTaggedObject(false, 1, unprotectedAttrs));
+        }
+        
+        return new BERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java
new file mode 100644
index 0000000..f02b1aa
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java
@@ -0,0 +1,77 @@
+package org.bouncycastle.asn1.cms;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.X509Name;
+
+public class IssuerAndSerialNumber
+    extends ASN1Encodable
+{
+    X509Name    name;
+    DERInteger  serialNumber;
+
+    public static IssuerAndSerialNumber getInstance(
+        Object  obj)
+    {
+        if (obj instanceof IssuerAndSerialNumber)
+        {
+            return (IssuerAndSerialNumber)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new IssuerAndSerialNumber((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException(
+            "Illegal object in IssuerAndSerialNumber: " + obj.getClass().getName());
+    }
+
+    public IssuerAndSerialNumber(
+        ASN1Sequence    seq)
+    {
+        this.name = X509Name.getInstance(seq.getObjectAt(0));
+        this.serialNumber = (DERInteger)seq.getObjectAt(1);
+    }
+
+    public IssuerAndSerialNumber(
+        X509Name    name,
+        BigInteger  serialNumber)
+    {
+        this.name = name;
+        this.serialNumber = new DERInteger(serialNumber);
+    }
+
+    public IssuerAndSerialNumber(
+        X509Name    name,
+        DERInteger  serialNumber)
+    {
+        this.name = name;
+        this.serialNumber = serialNumber;
+    }
+
+    public X509Name getName()
+    {
+        return name;
+    }
+
+    public DERInteger getSerialNumber()
+    {
+        return serialNumber;
+    }
+
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector    v = new ASN1EncodableVector();
+
+        v.add(name);
+        v.add(serialNumber);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/KEKIdentifier.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/KEKIdentifier.java
new file mode 100644
index 0000000..708487e
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/KEKIdentifier.java
@@ -0,0 +1,139 @@
+package org.bouncycastle.asn1.cms;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERGeneralizedTime;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+
+public class KEKIdentifier
+    extends ASN1Encodable
+{
+    private ASN1OctetString    keyIdentifier;
+    private DERGeneralizedTime date;
+    private OtherKeyAttribute  other;
+    
+    public KEKIdentifier(
+        byte[]              keyIdentifier,
+        DERGeneralizedTime  date,
+        OtherKeyAttribute   other)
+    {
+        this.keyIdentifier = new DEROctetString(keyIdentifier);
+        this.date = date;
+        this.other = other;
+    }
+    
+    public KEKIdentifier(
+        ASN1Sequence seq)
+    {
+        keyIdentifier = (ASN1OctetString)seq.getObjectAt(0);
+        
+        switch (seq.size())
+        {
+        case 1:
+            break;
+        case 2:
+            if (seq.getObjectAt(1) instanceof DERGeneralizedTime)
+            {
+                date = (DERGeneralizedTime)seq.getObjectAt(1); 
+            }
+            else
+            {
+                other = OtherKeyAttribute.getInstance(seq.getObjectAt(1));
+            }
+            break;
+        case 3:
+            date  = (DERGeneralizedTime)seq.getObjectAt(1);
+            other = OtherKeyAttribute.getInstance(seq.getObjectAt(2));
+            break;
+        default:
+                throw new IllegalArgumentException("Invalid KEKIdentifier");
+        }
+    }
+
+    /**
+     * return a KEKIdentifier object from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want.
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the object held by the
+     *          tagged object cannot be converted.
+     */
+    public static KEKIdentifier getInstance(
+        ASN1TaggedObject obj,
+        boolean explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+    
+    /**
+     * return a KEKIdentifier object from the given object.
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static KEKIdentifier getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof KEKIdentifier)
+        {
+            return (KEKIdentifier)obj;
+        }
+        
+        if (obj instanceof ASN1Sequence)
+        {
+            return new KEKIdentifier((ASN1Sequence)obj);
+        }
+        
+        throw new IllegalArgumentException("Invalid KEKIdentifier: " + obj.getClass().getName());
+    }
+
+    public ASN1OctetString getKeyIdentifier()
+    {
+        return keyIdentifier;
+    }
+
+    public DERGeneralizedTime getDate()
+    {
+        return date;
+    }
+
+    public OtherKeyAttribute getOther()
+    {
+        return other;
+    }
+
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * KEKIdentifier ::= SEQUENCE {
+     *     keyIdentifier OCTET STRING,
+     *     date GeneralizedTime OPTIONAL,
+     *     other OtherKeyAttribute OPTIONAL 
+     * }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(keyIdentifier);
+        
+        if (date != null)
+        {
+            v.add(date);
+        }
+
+        if (other != null)
+        {
+            v.add(other);
+        }
+        
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/KEKRecipientInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/KEKRecipientInfo.java
new file mode 100644
index 0000000..ddbcf13
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/KEKRecipientInfo.java
@@ -0,0 +1,121 @@
+package org.bouncycastle.asn1.cms;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class KEKRecipientInfo
+    extends ASN1Encodable
+{
+    private DERInteger          version;
+    private KEKIdentifier       kekid;
+    private AlgorithmIdentifier keyEncryptionAlgorithm;
+    private ASN1OctetString     encryptedKey;
+
+    public KEKRecipientInfo(
+        KEKIdentifier       kekid,
+        AlgorithmIdentifier keyEncryptionAlgorithm,
+        ASN1OctetString     encryptedKey)
+    {
+        this.version = new DERInteger(4);
+        this.kekid = kekid;
+        this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+        this.encryptedKey = encryptedKey;
+    }
+    
+    public KEKRecipientInfo(
+        ASN1Sequence seq)
+    {
+        version = (DERInteger)seq.getObjectAt(0);
+        kekid = KEKIdentifier.getInstance(seq.getObjectAt(1));
+        keyEncryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(2));
+        encryptedKey = (ASN1OctetString)seq.getObjectAt(3);
+    }
+
+    /**
+     * return a KEKRecipientInfo object from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want.
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the object held by the
+     *          tagged object cannot be converted.
+     */
+    public static KEKRecipientInfo getInstance(
+        ASN1TaggedObject    obj,
+        boolean             explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+    
+    /**
+     * return a KEKRecipientInfo object from the given object.
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static KEKRecipientInfo getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof KEKRecipientInfo)
+        {
+            return (KEKRecipientInfo)obj;
+        }
+        
+        if(obj instanceof ASN1Sequence)
+        {
+            return new KEKRecipientInfo((ASN1Sequence)obj);
+        }
+        
+        throw new IllegalArgumentException("Invalid KEKRecipientInfo: " + obj.getClass().getName());
+    }
+
+    public DERInteger getVersion()
+    {
+        return version;
+    }
+    
+    public KEKIdentifier getKekid()
+    {
+        return kekid;
+    }
+
+    public AlgorithmIdentifier getKeyEncryptionAlgorithm()
+    {
+        return keyEncryptionAlgorithm;
+    }
+
+    public ASN1OctetString getEncryptedKey()
+    {
+        return encryptedKey;
+    }
+
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * KEKRecipientInfo ::= SEQUENCE {
+     *     version CMSVersion,  -- always set to 4
+     *     kekid KEKIdentifier,
+     *     keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+     *     encryptedKey EncryptedKey 
+     * }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(version);
+        v.add(kekid);
+        v.add(keyEncryptionAlgorithm);
+        v.add(encryptedKey);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/KeyAgreeRecipientInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/KeyAgreeRecipientInfo.java
new file mode 100644
index 0000000..5ebf4dc
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/KeyAgreeRecipientInfo.java
@@ -0,0 +1,151 @@
+package org.bouncycastle.asn1.cms;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class KeyAgreeRecipientInfo
+    extends ASN1Encodable
+{
+    private DERInteger                  version;
+    private OriginatorIdentifierOrKey   originator;
+    private ASN1OctetString             ukm;
+    private AlgorithmIdentifier         keyEncryptionAlgorithm;
+    private ASN1Sequence                recipientEncryptedKeys;
+    
+    public KeyAgreeRecipientInfo(
+        OriginatorIdentifierOrKey   originator,
+        ASN1OctetString             ukm,
+        AlgorithmIdentifier         keyEncryptionAlgorithm,
+        ASN1Sequence                recipientEncryptedKeys)
+    {
+        this.version = new DERInteger(3);
+        this.originator = originator;
+        this.ukm = ukm;
+        this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+        this.recipientEncryptedKeys = recipientEncryptedKeys;
+    }
+    
+    public KeyAgreeRecipientInfo(
+        ASN1Sequence seq)
+    {
+        int index = 0;
+        
+        version = (DERInteger)seq.getObjectAt(index++);
+        originator = OriginatorIdentifierOrKey.getInstance(
+                            (ASN1TaggedObject)seq.getObjectAt(index++), true);
+
+        if (seq.getObjectAt(index) instanceof ASN1TaggedObject)
+        {
+            ukm = ASN1OctetString.getInstance(
+                            (ASN1TaggedObject)seq.getObjectAt(index++), true);
+        }
+
+        keyEncryptionAlgorithm = AlgorithmIdentifier.getInstance(
+                                                seq.getObjectAt(index++));
+
+        recipientEncryptedKeys = (ASN1Sequence)seq.getObjectAt(index++);
+    }
+    
+    /**
+     * return a KeyAgreeRecipientInfo object from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want.
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the object held by the
+     *          tagged object cannot be converted.
+     */
+    public static KeyAgreeRecipientInfo getInstance(
+        ASN1TaggedObject    obj,
+        boolean             explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+    
+    /**
+     * return a KeyAgreeRecipientInfo object from the given object.
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static KeyAgreeRecipientInfo getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof KeyAgreeRecipientInfo)
+        {
+            return (KeyAgreeRecipientInfo)obj;
+        }
+        
+        if (obj instanceof ASN1Sequence)
+        {
+            return new KeyAgreeRecipientInfo((ASN1Sequence)obj);
+        }
+        
+        throw new IllegalArgumentException(
+        "Illegal object in KeyAgreeRecipientInfo: " + obj.getClass().getName());
+
+    } 
+
+    public DERInteger getVersion()
+    {
+        return version;
+    }
+
+    public OriginatorIdentifierOrKey getOriginator()
+    {
+        return originator;
+    }
+
+    public ASN1OctetString getUserKeyingMaterial()
+    {
+        return ukm;
+    }
+
+    public AlgorithmIdentifier getKeyEncryptionAlgorithm()
+    {
+        return keyEncryptionAlgorithm;
+    }
+
+    public ASN1Sequence getRecipientEncryptedKeys()
+    {
+        return recipientEncryptedKeys;
+    }
+
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * KeyAgreeRecipientInfo ::= SEQUENCE {
+     *     version CMSVersion,  -- always set to 3
+     *     originator [0] EXPLICIT OriginatorIdentifierOrKey,
+     *     ukm [1] EXPLICIT UserKeyingMaterial OPTIONAL,
+     *     keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+     *     recipientEncryptedKeys RecipientEncryptedKeys 
+     * }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(version);
+        v.add(new DERTaggedObject(true, 0, originator));
+        
+        if (ukm != null)
+        {
+            v.add(new DERTaggedObject(true, 1, ukm));
+        }
+        
+        v.add(keyEncryptionAlgorithm);
+        v.add(recipientEncryptedKeys);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/KeyTransRecipientInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/KeyTransRecipientInfo.java
new file mode 100644
index 0000000..70553b7
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/KeyTransRecipientInfo.java
@@ -0,0 +1,114 @@
+package org.bouncycastle.asn1.cms;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class KeyTransRecipientInfo
+    extends ASN1Encodable
+{
+    private DERInteger          version;
+    private RecipientIdentifier rid;
+    private AlgorithmIdentifier keyEncryptionAlgorithm;
+    private ASN1OctetString     encryptedKey;
+
+    public KeyTransRecipientInfo(
+        RecipientIdentifier rid,
+        AlgorithmIdentifier keyEncryptionAlgorithm,
+        ASN1OctetString     encryptedKey)
+    {
+        if (rid.getDERObject() instanceof ASN1TaggedObject)
+        {
+            this.version = new DERInteger(2);
+        }
+        else
+        {
+            this.version = new DERInteger(0);
+        }
+
+        this.rid = rid;
+        this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+        this.encryptedKey = encryptedKey;
+    }
+    
+    public KeyTransRecipientInfo(
+        ASN1Sequence seq)
+    {
+        this.version = (DERInteger)seq.getObjectAt(0);
+        this.rid = RecipientIdentifier.getInstance(seq.getObjectAt(1));
+        this.keyEncryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(2));
+        this.encryptedKey = (ASN1OctetString)seq.getObjectAt(3);
+    }
+
+    /**
+     * return a KeyTransRecipientInfo object from the given object.
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static KeyTransRecipientInfo getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof KeyTransRecipientInfo)
+        {
+            return (KeyTransRecipientInfo)obj;
+        }
+        
+        if(obj instanceof ASN1Sequence)
+        {
+            return new KeyTransRecipientInfo((ASN1Sequence)obj);
+        }
+        
+        throw new IllegalArgumentException(
+        "Illegal object in KeyTransRecipientInfo: " + obj.getClass().getName());
+    } 
+
+    public DERInteger getVersion()
+    {
+        return version;
+    }
+
+    public RecipientIdentifier getRecipientIdentifier()
+    {
+        return rid;
+    }
+
+    public AlgorithmIdentifier getKeyEncryptionAlgorithm()
+    {
+        return keyEncryptionAlgorithm;
+    }
+
+    public ASN1OctetString getEncryptedKey()
+    {
+        return encryptedKey;
+    }
+
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * KeyTransRecipientInfo ::= SEQUENCE {
+     *     version CMSVersion,  -- always set to 0 or 2
+     *     rid RecipientIdentifier,
+     *     keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+     *     encryptedKey EncryptedKey 
+     * }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(version);
+        v.add(rid);
+        v.add(keyEncryptionAlgorithm);
+        v.add(encryptedKey);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/OriginatorIdentifierOrKey.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/OriginatorIdentifierOrKey.java
new file mode 100644
index 0000000..f9d3c21
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/OriginatorIdentifierOrKey.java
@@ -0,0 +1,104 @@
+package org.bouncycastle.asn1.cms;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+public class OriginatorIdentifierOrKey
+    extends ASN1Encodable
+{
+    private DEREncodable id;
+    
+    public OriginatorIdentifierOrKey(
+        IssuerAndSerialNumber id)
+    {
+        this.id = id;
+    }
+    
+    public OriginatorIdentifierOrKey(
+        ASN1OctetString id)
+    {
+        this.id = new DERTaggedObject(false, 0, id);
+    }
+    
+    public OriginatorIdentifierOrKey(
+        OriginatorPublicKey id)
+    {
+        this.id = new DERTaggedObject(false, 1, id);
+    }
+    
+    public OriginatorIdentifierOrKey(
+        DERObject id)
+    {
+        this.id = id;
+    }
+    
+    /**
+     * return an OriginatorIdentifierOrKey object from a tagged object.
+     *
+     * @param o the tagged object holding the object we want.
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the object held by the
+     *          tagged object cannot be converted.
+     */
+    public static OriginatorIdentifierOrKey getInstance(
+        ASN1TaggedObject    o,
+        boolean             explicit)
+    {
+        if (!explicit)
+        {
+            throw new IllegalArgumentException(
+                    "Can't implicitly tag OriginatorIdentifierOrKey");
+        }
+
+        return getInstance(o.getObject());
+    }
+    
+    /**
+     * return an OriginatorIdentifierOrKey object from the given object.
+     *
+     * @param o the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static OriginatorIdentifierOrKey getInstance(
+        Object o)
+    {
+        if (o == null || o instanceof OriginatorIdentifierOrKey)
+        {
+            return (OriginatorIdentifierOrKey)o;
+        }
+        
+        if (o instanceof DERObject)
+        {
+            return new OriginatorIdentifierOrKey((DERObject)o);
+        }
+        
+        throw new IllegalArgumentException("Invalid OriginatorIdentifierOrKey: " + o.getClass().getName());
+    } 
+
+    public DEREncodable getId()
+    {
+        return id;
+    }
+    
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * OriginatorIdentifierOrKey ::= CHOICE {
+     *     issuerAndSerialNumber IssuerAndSerialNumber,
+     *     subjectKeyIdentifier [0] SubjectKeyIdentifier,
+     *     originatorKey [1] OriginatorPublicKey 
+     * }
+     *
+     * SubjectKeyIdentifier ::= OCTET STRING
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        return id.getDERObject();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/OriginatorInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/OriginatorInfo.java
new file mode 100644
index 0000000..50d2edc
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/OriginatorInfo.java
@@ -0,0 +1,129 @@
+package org.bouncycastle.asn1.cms;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+public class OriginatorInfo
+    extends ASN1Encodable
+{
+    private ASN1Set certs;
+    private ASN1Set crls;
+    
+    public OriginatorInfo(
+        ASN1Set certs,
+        ASN1Set crls)
+    {
+        this.certs = certs;
+        this.crls = crls;
+    }
+    
+    public OriginatorInfo(
+        ASN1Sequence seq)
+    {
+        switch (seq.size())
+        {
+        case 0:     // empty
+            break;
+        case 1:
+            ASN1TaggedObject o = (ASN1TaggedObject)seq.getObjectAt(0);
+            switch (o.getTagNo())
+            {
+            case 0 :
+                certs = ASN1Set.getInstance(o, false);
+                break;
+            case 1 :
+                crls = ASN1Set.getInstance(o, false);
+                break;
+            default:
+                throw new IllegalArgumentException("Bad tag in OriginatorInfo: " + o.getTagNo());
+            }
+            break;
+        case 2:
+            certs = ASN1Set.getInstance((ASN1TaggedObject)seq.getObjectAt(0), false);
+            crls  = ASN1Set.getInstance((ASN1TaggedObject)seq.getObjectAt(1), false);
+            break;
+        default:
+            throw new IllegalArgumentException("OriginatorInfo too big");
+        }
+    }
+    
+    /**
+     * return an OriginatorInfo object from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want.
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the object held by the
+     *          tagged object cannot be converted.
+     */
+    public static OriginatorInfo getInstance(
+        ASN1TaggedObject    obj,
+        boolean             explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+    
+    /**
+     * return an OriginatorInfo object from the given object.
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static OriginatorInfo getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof OriginatorInfo)
+        {
+            return (OriginatorInfo)obj;
+        }
+        
+        if (obj instanceof ASN1Sequence)
+        {
+            return new OriginatorInfo((ASN1Sequence)obj);
+        }
+        
+        throw new IllegalArgumentException("Invalid OriginatorInfo: " + obj.getClass().getName());
+    }
+    
+    public ASN1Set getCertificates()
+    {
+        return certs;
+    }
+
+    public ASN1Set getCRLs()
+    {
+        return crls;
+    }
+
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * OriginatorInfo ::= SEQUENCE {
+     *     certs [0] IMPLICIT CertificateSet OPTIONAL,
+     *     crls [1] IMPLICIT CertificateRevocationLists OPTIONAL 
+     * }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        if (certs != null)
+        {
+            v.add(new DERTaggedObject(false, 0, certs));
+        }
+        
+        if (crls != null)
+        {
+            v.add(new DERTaggedObject(false, 1, crls));
+        }
+        
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/OriginatorPublicKey.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/OriginatorPublicKey.java
new file mode 100644
index 0000000..826761d
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/OriginatorPublicKey.java
@@ -0,0 +1,100 @@
+package org.bouncycastle.asn1.cms;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+
+public class OriginatorPublicKey
+    extends ASN1Encodable
+{
+    private AlgorithmIdentifier algorithm;
+    private DERBitString        publicKey;
+    
+    public OriginatorPublicKey(
+        AlgorithmIdentifier algorithm,
+        byte[]              publicKey)
+    {
+        this.algorithm = algorithm;
+        this.publicKey = new DERBitString(publicKey);
+    }
+    
+    public OriginatorPublicKey(
+        ASN1Sequence seq)
+    {
+        algorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0));
+        publicKey = (DERBitString)seq.getObjectAt(1);
+    }
+    
+    /**
+     * return an OriginatorPublicKey object from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want.
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the object held by the
+     *          tagged object cannot be converted.
+     */
+    public static OriginatorPublicKey getInstance(
+        ASN1TaggedObject    obj,
+        boolean             explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+    
+    /**
+     * return an OriginatorPublicKey object from the given object.
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static OriginatorPublicKey getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof OriginatorPublicKey)
+        {
+            return (OriginatorPublicKey)obj;
+        }
+        
+        if (obj instanceof ASN1Sequence)
+        {
+            return new OriginatorPublicKey((ASN1Sequence)obj);
+        }
+        
+        throw new IllegalArgumentException("Invalid OriginatorPublicKey: " + obj.getClass().getName());
+    } 
+
+    public AlgorithmIdentifier getAlgorithm()
+    {
+        return algorithm;
+    }
+
+    public DERBitString getPublicKey()
+    {
+        return publicKey;
+    }
+
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * OriginatorPublicKey ::= SEQUENCE {
+     *     algorithm AlgorithmIdentifier,
+     *     publicKey BIT STRING 
+     * }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(algorithm);
+        v.add(publicKey);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/OtherKeyAttribute.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/OtherKeyAttribute.java
new file mode 100644
index 0000000..1232363
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/OtherKeyAttribute.java
@@ -0,0 +1,82 @@
+package org.bouncycastle.asn1.cms;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+
+public class OtherKeyAttribute
+    extends ASN1Encodable
+{
+    private DERObjectIdentifier keyAttrId;
+    private DEREncodable        keyAttr;
+
+    /**
+     * return an OtherKeyAttribute object from the given object.
+     *
+     * @param o the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static OtherKeyAttribute getInstance(
+        Object o)
+    {
+        if (o == null || o instanceof OtherKeyAttribute)
+        {
+            return (OtherKeyAttribute)o;
+        }
+        
+        if (o instanceof ASN1Sequence)
+        {
+            return new OtherKeyAttribute((ASN1Sequence)o);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+    
+    public OtherKeyAttribute(
+        ASN1Sequence seq)
+    {
+        keyAttrId = (DERObjectIdentifier)seq.getObjectAt(0);
+        keyAttr = seq.getObjectAt(1);
+    }
+
+    public OtherKeyAttribute(
+        DERObjectIdentifier keyAttrId,
+        DEREncodable        keyAttr)
+    {
+        this.keyAttrId = keyAttrId;
+        this.keyAttr = keyAttr;
+    }
+
+    public DERObjectIdentifier getKeyAttrId()
+    {
+        return keyAttrId;
+    }
+    
+    public DEREncodable getKeyAttr()
+    {
+        return keyAttr;
+    }
+
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * OtherKeyAttribute ::= SEQUENCE {
+     *     keyAttrId OBJECT IDENTIFIER,
+     *     keyAttr ANY DEFINED BY keyAttrId OPTIONAL
+     * }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(keyAttrId);
+        v.add(keyAttr);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/OtherRecipientInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/OtherRecipientInfo.java
new file mode 100644
index 0000000..e70c43c
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/OtherRecipientInfo.java
@@ -0,0 +1,98 @@
+package org.bouncycastle.asn1.cms;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+
+public class OtherRecipientInfo
+    extends ASN1Encodable
+{
+    private DERObjectIdentifier    oriType;
+    private DEREncodable           oriValue;
+
+    public OtherRecipientInfo(
+        DERObjectIdentifier     oriType,
+        DEREncodable            oriValue)
+    {
+        this.oriType = oriType;
+        this.oriValue = oriValue;
+    }
+    
+    public OtherRecipientInfo(
+        ASN1Sequence seq)
+    {
+        oriType = DERObjectIdentifier.getInstance(seq.getObjectAt(1));
+        oriValue = seq.getObjectAt(2);
+    }
+
+    /**
+     * return a OtherRecipientInfo object from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want.
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the object held by the
+     *          tagged object cannot be converted.
+     */
+    public static OtherRecipientInfo getInstance(
+        ASN1TaggedObject    obj,
+        boolean             explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+    
+    /**
+     * return a OtherRecipientInfo object from the given object.
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static OtherRecipientInfo getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof OtherRecipientInfo)
+        {
+            return (OtherRecipientInfo)obj;
+        }
+        
+        if (obj instanceof ASN1Sequence)
+        {
+            return new OtherRecipientInfo((ASN1Sequence)obj);
+        }
+        
+        throw new IllegalArgumentException("Invalid OtherRecipientInfo: " + obj.getClass().getName());
+    }
+
+    public DERObjectIdentifier getType()
+    {
+        return oriType;
+    }
+
+    public DEREncodable getValue()
+    {
+        return oriValue;
+    }
+
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * OtherRecipientInfo ::= SEQUENCE {
+     *    oriType OBJECT IDENTIFIER,
+     *    oriValue ANY DEFINED BY oriType }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(oriType);
+        v.add(oriValue);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/PasswordRecipientInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/PasswordRecipientInfo.java
new file mode 100644
index 0000000..555a820
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/PasswordRecipientInfo.java
@@ -0,0 +1,143 @@
+package org.bouncycastle.asn1.cms;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class PasswordRecipientInfo
+    extends ASN1Encodable
+{
+    private DERInteger          version;
+    private AlgorithmIdentifier keyDerivationAlgorithm;
+    private AlgorithmIdentifier keyEncryptionAlgorithm;
+    private ASN1OctetString     encryptedKey;
+
+    public PasswordRecipientInfo(
+        AlgorithmIdentifier     keyEncryptionAlgorithm,
+        ASN1OctetString         encryptedKey)
+    {
+        this.version = new DERInteger(0);
+        this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+        this.encryptedKey = encryptedKey;
+    }
+    
+    public PasswordRecipientInfo(
+        AlgorithmIdentifier     keyDerivationAlgorithm,
+        AlgorithmIdentifier     keyEncryptionAlgorithm,
+        ASN1OctetString         encryptedKey)
+    {
+        this.version = new DERInteger(0);
+        this.keyDerivationAlgorithm = keyDerivationAlgorithm;
+        this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+        this.encryptedKey = encryptedKey;
+    }
+    
+    public PasswordRecipientInfo(
+        ASN1Sequence seq)
+    {
+        version = (DERInteger)seq.getObjectAt(0);
+        if (seq.getObjectAt(1) instanceof ASN1TaggedObject)
+        {
+            keyDerivationAlgorithm = AlgorithmIdentifier.getInstance((ASN1TaggedObject)seq.getObjectAt(1), false);
+            keyEncryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(2));
+            encryptedKey = (ASN1OctetString)seq.getObjectAt(3);
+        }
+        else
+        {
+            keyEncryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
+            encryptedKey = (ASN1OctetString)seq.getObjectAt(2);
+        }
+    }
+
+    /**
+     * return a PasswordRecipientInfo object from a tagged object.
+     *
+     * @param obj the tagged object holding the object we want.
+     * @param explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the object held by the
+     *          tagged object cannot be converted.
+     */
+    public static PasswordRecipientInfo getInstance(
+        ASN1TaggedObject    obj,
+        boolean             explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+    
+    /**
+     * return a PasswordRecipientInfo object from the given object.
+     *
+     * @param obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static PasswordRecipientInfo getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof PasswordRecipientInfo)
+        {
+            return (PasswordRecipientInfo)obj;
+        }
+        
+        if(obj instanceof ASN1Sequence)
+        {
+            return new PasswordRecipientInfo((ASN1Sequence)obj);
+        }
+        
+        throw new IllegalArgumentException("Invalid PasswordRecipientInfo: " + obj.getClass().getName());
+    }
+
+    public DERInteger getVersion()
+    {
+        return version;
+    }
+
+    public AlgorithmIdentifier getKeyDerivationAlgorithm()
+    {
+        return keyDerivationAlgorithm;
+    }
+
+    public AlgorithmIdentifier getKeyEncryptionAlgorithm()
+    {
+        return keyEncryptionAlgorithm;
+    }
+
+    public ASN1OctetString getEncryptedKey()
+    {
+        return encryptedKey;
+    }
+
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * PasswordRecipientInfo ::= SEQUENCE {
+     *   version CMSVersion,   -- Always set to 0
+     *   keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier
+     *                             OPTIONAL,
+     *  keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+     *  encryptedKey EncryptedKey }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(version);
+        
+        if (keyDerivationAlgorithm != null)
+        {
+            v.add(new DERTaggedObject(false, 0, keyDerivationAlgorithm));
+        }
+        v.add(keyEncryptionAlgorithm);
+        v.add(encryptedKey);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/RecipientIdentifier.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/RecipientIdentifier.java
new file mode 100644
index 0000000..2578583
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/RecipientIdentifier.java
@@ -0,0 +1,96 @@
+package org.bouncycastle.asn1.cms;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+public class RecipientIdentifier
+    extends ASN1Encodable
+{
+    private DEREncodable id;
+    
+    public RecipientIdentifier(
+        IssuerAndSerialNumber id)
+    {
+        this.id = id;
+    }
+    
+    public RecipientIdentifier(
+        ASN1OctetString id)
+    {
+        this.id = new DERTaggedObject(false, 0, id);
+    }
+    
+    public RecipientIdentifier(
+        DERObject id)
+    {
+        this.id = id;
+    }
+    
+    /**
+     * return a RecipientIdentifier object from the given object.
+     *
+     * @param o the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static RecipientIdentifier getInstance(
+        Object o)
+    {
+        if (o == null || o instanceof RecipientIdentifier)
+        {
+            return (RecipientIdentifier)o;
+        }
+        
+        if (o instanceof IssuerAndSerialNumber)
+        {
+            return new RecipientIdentifier((IssuerAndSerialNumber)o);
+        }
+        
+        if (o instanceof ASN1OctetString)
+        {
+            return new RecipientIdentifier((ASN1OctetString)o);
+        }
+        
+        if (o instanceof DERObject)
+        {
+            return new RecipientIdentifier((DERObject)o);
+        }
+        
+        throw new IllegalArgumentException(
+          "Illegal object in RecipientIdentifier: " + o.getClass().getName());
+    } 
+
+    public boolean isTagged()
+    {
+        return (id instanceof ASN1TaggedObject);
+    }
+
+    public DEREncodable getId()
+    {
+        if (id instanceof ASN1TaggedObject)
+        {
+            return ASN1OctetString.getInstance((ASN1TaggedObject)id, false);
+        }
+
+        return IssuerAndSerialNumber.getInstance(id);
+    }
+
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * RecipientIdentifier ::= CHOICE {
+     *     issuerAndSerialNumber IssuerAndSerialNumber,
+     *     subjectKeyIdentifier [0] SubjectKeyIdentifier 
+     * }
+     *
+     * SubjectKeyIdentifier ::= OCTET STRING
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        return id.getDERObject();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/RecipientInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/RecipientInfo.java
new file mode 100644
index 0000000..13f98f2
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/RecipientInfo.java
@@ -0,0 +1,140 @@
+package org.bouncycastle.asn1.cms;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+public class RecipientInfo
+    extends ASN1Encodable
+{
+    DEREncodable    info;
+
+    public RecipientInfo(
+        KeyTransRecipientInfo info)
+    {
+        this.info = info;
+    }
+
+    public RecipientInfo(
+        KeyAgreeRecipientInfo info)
+    {
+        this.info = new DERTaggedObject(true, 1, info);
+    }
+
+    public RecipientInfo(
+        KEKRecipientInfo info)
+    {
+        this.info = new DERTaggedObject(true, 2, info);
+    }
+
+    public RecipientInfo(
+        PasswordRecipientInfo info)
+    {
+        this.info = new DERTaggedObject(true, 3, info);
+    }
+
+    public RecipientInfo(
+        OtherRecipientInfo info)
+    {
+        this.info = new DERTaggedObject(true, 4, info);
+    }
+
+    public RecipientInfo(
+        DERObject   info)
+    {
+        this.info = info;
+    }
+
+    public static RecipientInfo getInstance(
+        Object  o)
+    {
+        if (o == null || o instanceof RecipientInfo)
+        {
+            return (RecipientInfo)o;
+        }
+        else if (o instanceof ASN1Sequence)
+        {
+            return new RecipientInfo((ASN1Sequence)o);
+        }
+        else if (o instanceof ASN1TaggedObject)
+        {
+            return new RecipientInfo((ASN1TaggedObject)o);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory: "
+                                                    + o.getClass().getName());
+    }
+
+    public DERInteger getVersion()
+    {
+        if (info instanceof ASN1TaggedObject)
+        {
+            ASN1TaggedObject o = (ASN1TaggedObject)info;
+
+            switch (o.getTagNo())
+            {
+            case 1:
+                return KeyAgreeRecipientInfo.getInstance(o, true).getVersion();
+            case 2:
+                return KEKRecipientInfo.getInstance(o, true).getVersion();
+            case 3:
+                return PasswordRecipientInfo.getInstance(o, true).getVersion();
+            case 4:
+                return new DERInteger(0);    // no syntax version for OtherRecipientInfo
+            default:
+                throw new IllegalStateException("unknown tag");
+            }
+        }
+
+        return KeyTransRecipientInfo.getInstance(info).getVersion();
+    }
+
+    public boolean isTagged()
+    {
+        return (info instanceof ASN1TaggedObject);
+    }
+
+    public DEREncodable getInfo()
+    {
+        if (info instanceof ASN1TaggedObject)
+        {
+            ASN1TaggedObject o = (ASN1TaggedObject)info;
+
+            switch (o.getTagNo())
+            {
+            case 1:
+                return KeyAgreeRecipientInfo.getInstance(o, true);
+            case 2:
+                return KEKRecipientInfo.getInstance(o, true);
+            case 3:
+                return PasswordRecipientInfo.getInstance(o, true);
+            case 4:
+                return OtherRecipientInfo.getInstance(o, true);
+            default:
+                throw new IllegalStateException("unknown tag");
+            }
+        }
+
+        return KeyTransRecipientInfo.getInstance(info);
+    }
+
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * RecipientInfo ::= CHOICE {
+     *     ktri KeyTransRecipientInfo,
+     *     kari [1] KeyAgreeRecipientInfo,
+     *     kekri [2] KEKRecipientInfo,
+     *     pwri [3] PasswordRecipientInfo,
+     *     ori [4] OtherRecipientInfo }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        return info.getDERObject();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/RecipientKeyIdentifier.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/RecipientKeyIdentifier.java
new file mode 100644
index 0000000..f7e3b19
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/RecipientKeyIdentifier.java
@@ -0,0 +1,139 @@
+package org.bouncycastle.asn1.cms;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERGeneralizedTime;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+public class RecipientKeyIdentifier
+    extends ASN1Encodable
+{
+    private ASN1OctetString      subjectKeyIdentifier;
+    private DERGeneralizedTime   date;
+    private OtherKeyAttribute    other;
+
+    public RecipientKeyIdentifier(
+        ASN1OctetString         subjectKeyIdentifier,
+        DERGeneralizedTime      date,
+        OtherKeyAttribute       other)
+    {
+        this.subjectKeyIdentifier = subjectKeyIdentifier;
+        this.date = date;
+        this.other = other;
+    }
+    
+    public RecipientKeyIdentifier(
+        ASN1Sequence seq)
+    {
+        subjectKeyIdentifier = ASN1OctetString.getInstance(
+                                                    seq.getObjectAt(0));
+        
+        switch(seq.size())
+        {
+        case 1:
+            break;
+        case 2:
+            if (seq.getObjectAt(1) instanceof DERGeneralizedTime)
+            {
+                date = (DERGeneralizedTime)seq.getObjectAt(1); 
+            }
+            else
+            {
+                other = OtherKeyAttribute.getInstance(seq.getObjectAt(2));
+            }
+            break;
+        case 3:
+            date  = (DERGeneralizedTime)seq.getObjectAt(1);
+            other = OtherKeyAttribute.getInstance(seq.getObjectAt(2));
+            break;
+        default:
+            throw new IllegalArgumentException("Invalid KEKIdentifier");
+        }
+    }
+
+    /**
+     * return a RecipientKeyIdentifier object from a tagged object.
+     *
+     * @param _ato the tagged object holding the object we want.
+     * @param _explicit true if the object is meant to be explicitly
+     *              tagged false otherwise.
+     * @exception IllegalArgumentException if the object held by the
+     *          tagged object cannot be converted.
+     */
+    public static RecipientKeyIdentifier getInstance(ASN1TaggedObject _ato, boolean _explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(_ato, _explicit));
+    }
+    
+    /**
+     * return a RecipientKeyIdentifier object from the given object.
+     *
+     * @param _obj the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static RecipientKeyIdentifier getInstance(Object _obj)
+    {
+        if(_obj == null || _obj instanceof RecipientKeyIdentifier)
+        {
+            return (RecipientKeyIdentifier)_obj;
+        }
+        
+        if(_obj instanceof ASN1Sequence)
+        {
+            return new RecipientKeyIdentifier((ASN1Sequence)_obj);
+        }
+        
+        throw new IllegalArgumentException("Invalid RecipientKeyIdentifier: " + _obj.getClass().getName());
+    } 
+
+    public ASN1OctetString getSubjectKeyIdentifier()
+    {
+        return subjectKeyIdentifier;
+    }
+
+    public DERGeneralizedTime getDate()
+    {
+        return date;
+    }
+
+    public OtherKeyAttribute getOtherKeyAttribute()
+    {
+        return other;
+    }
+
+
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * RecipientKeyIdentifier ::= SEQUENCE {
+     *     subjectKeyIdentifier SubjectKeyIdentifier,
+     *     date GeneralizedTime OPTIONAL,
+     *     other OtherKeyAttribute OPTIONAL 
+     * }
+     *
+     * SubjectKeyIdentifier ::= OCTET STRING
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(subjectKeyIdentifier);
+        
+        if (date != null)
+        {
+            v.add(date);
+        }
+
+        if (other != null)
+        {
+            v.add(other);
+        }
+        
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/SignedData.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/SignedData.java
new file mode 100644
index 0000000..434395c
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/SignedData.java
@@ -0,0 +1,215 @@
+package org.bouncycastle.asn1.cms;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.BERSequence;
+import org.bouncycastle.asn1.BERTaggedObject;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * a signed data object.
+ */
+public class SignedData
+    extends ASN1Encodable
+{
+    private DERInteger  version;
+    private ASN1Set     digestAlgorithms;
+    private ContentInfo contentInfo;
+    private ASN1Set     certificates;
+    private ASN1Set     crls;
+    private ASN1Set     signerInfos;
+    private boolean        certBer;
+    private boolean        crlsBer;
+
+    public static SignedData getInstance(
+        Object  o)
+    {
+        if (o instanceof SignedData)
+        {
+            return (SignedData)o;
+        }
+        else if (o instanceof ASN1Sequence)
+        {
+            return new SignedData((ASN1Sequence)o);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public SignedData(
+        ASN1Set     digestAlgorithms,
+        ContentInfo contentInfo,
+        ASN1Set     certificates,
+        ASN1Set     crls,
+        ASN1Set     signerInfos)
+    {
+        if (contentInfo.getContentType().equals(CMSObjectIdentifiers.data))
+        {
+            //
+            // we should also be looking for attribute certificates here,
+            // later.
+            //
+            Enumeration e = signerInfos.getObjects();
+            boolean     v3Found = false;
+
+            while (e.hasMoreElements())
+            {
+                SignerInfo  s = SignerInfo.getInstance(e.nextElement());
+
+                if (s.getVersion().getValue().intValue() == 3)
+                {
+                    v3Found = true;
+                }
+            }
+
+            if (v3Found)
+            {
+                this.version = new DERInteger(3);
+            }
+            else
+            {
+                this.version = new DERInteger(1);
+            }
+        }
+        else
+        {
+            this.version = new DERInteger(3);
+        }
+
+        this.digestAlgorithms = digestAlgorithms;
+        this.contentInfo = contentInfo;
+        this.certificates = certificates;
+        this.crls = crls;
+        this.signerInfos = signerInfos;
+    }
+    
+    public SignedData(
+        ASN1Sequence seq)
+    {
+        Enumeration     e = seq.getObjects();
+
+        version = (DERInteger)e.nextElement();
+        digestAlgorithms = ((ASN1Set)e.nextElement());
+        contentInfo = ContentInfo.getInstance(e.nextElement());
+
+        while (e.hasMoreElements())
+        {
+            DERObject o = (DERObject)e.nextElement();
+
+            //
+            // an interesting feature of SignedData is that there appear
+            // to be varying implementations...
+            // for the moment we ignore anything which doesn't fit.
+            //
+            if (o instanceof ASN1TaggedObject)
+            {
+                ASN1TaggedObject tagged = (ASN1TaggedObject)o;
+
+                switch (tagged.getTagNo())
+                {
+                case 0:
+                    certBer = tagged instanceof BERTaggedObject;
+                    certificates = ASN1Set.getInstance(tagged, false);
+                    break;
+                case 1:
+                    crlsBer = tagged instanceof BERTaggedObject;
+                    crls = ASN1Set.getInstance(tagged, false);
+                    break;
+                default:
+                    throw new IllegalArgumentException("unknown tag value " + tagged.getTagNo());
+                }
+            }
+            else
+            {
+                signerInfos = (ASN1Set)o;
+            }
+        }
+    }
+
+    public DERInteger getVersion()
+    {
+        return version;
+    }
+
+    public ASN1Set getDigestAlgorithms()
+    {
+        return digestAlgorithms;
+    }
+
+    public ContentInfo getEncapContentInfo()
+    {
+        return contentInfo;
+    }
+
+    public ASN1Set getCertificates()
+    {
+        return certificates;
+    }
+
+    public ASN1Set getCRLs()
+    {
+        return crls;
+    }
+
+    public ASN1Set getSignerInfos()
+    {
+        return signerInfos;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * SignedData ::= SEQUENCE {
+     *     version CMSVersion,
+     *     digestAlgorithms DigestAlgorithmIdentifiers,
+     *     encapContentInfo EncapsulatedContentInfo,
+     *     certificates [0] IMPLICIT CertificateSet OPTIONAL,
+     *     crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+     *     signerInfos SignerInfos
+     *   }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(version);
+        v.add(digestAlgorithms);
+        v.add(contentInfo);
+
+        if (certificates != null)
+        {
+            if (certBer)
+            {
+                v.add(new BERTaggedObject(false, 0, certificates));
+            }
+            else
+            {
+                v.add(new DERTaggedObject(false, 0, certificates));
+            }
+        }
+
+        if (crls != null)
+        {
+            if (crlsBer)
+            {
+                v.add(new BERTaggedObject(false, 1, crls));
+            }
+            else
+            {
+                v.add(new DERTaggedObject(false, 1, crls));
+            }
+        }
+
+        v.add(signerInfos);
+
+        return new BERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/SignerIdentifier.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/SignerIdentifier.java
new file mode 100644
index 0000000..41b8c57
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/SignerIdentifier.java
@@ -0,0 +1,96 @@
+package org.bouncycastle.asn1.cms;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+public class SignerIdentifier
+    extends ASN1Encodable
+{
+    private DEREncodable id;
+    
+    public SignerIdentifier(
+        IssuerAndSerialNumber id)
+    {
+        this.id = id;
+    }
+    
+    public SignerIdentifier(
+        ASN1OctetString id)
+    {
+        this.id = new DERTaggedObject(false, 0, id);
+    }
+    
+    public SignerIdentifier(
+        DERObject id)
+    {
+        this.id = id;
+    }
+    
+    /**
+     * return a SignerIdentifier object from the given object.
+     *
+     * @param o the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static SignerIdentifier getInstance(
+        Object o)
+    {
+        if (o == null || o instanceof SignerIdentifier)
+        {
+            return (SignerIdentifier)o;
+        }
+        
+        if (o instanceof IssuerAndSerialNumber)
+        {
+            return new SignerIdentifier((IssuerAndSerialNumber)o);
+        }
+        
+        if (o instanceof ASN1OctetString)
+        {
+            return new SignerIdentifier((ASN1OctetString)o);
+        }
+        
+        if (o instanceof DERObject)
+        {
+            return new SignerIdentifier((DERObject)o);
+        }
+        
+        throw new IllegalArgumentException(
+             "Illegal object in SignerIdentifier: " + o.getClass().getName());
+    } 
+
+    public boolean isTagged()
+    {
+        return (id instanceof ASN1TaggedObject);
+    }
+
+    public DEREncodable getId()
+    {
+        if (id instanceof ASN1TaggedObject)
+        {
+            return ASN1OctetString.getInstance((ASN1TaggedObject)id, false);
+        }
+
+        return id;
+    }
+
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * SignerIdentifier ::= CHOICE {
+     *     issuerAndSerialNumber IssuerAndSerialNumber,
+     *     subjectKeyIdentifier [0] SubjectKeyIdentifier 
+     * }
+     *
+     * SubjectKeyIdentifier ::= OCTET STRING
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        return id.getDERObject();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java
new file mode 100644
index 0000000..83a1f53
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java
@@ -0,0 +1,172 @@
+package org.bouncycastle.asn1.cms;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.*;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class SignerInfo
+    extends ASN1Encodable
+{
+    private DERInteger              version;
+    private SignerIdentifier        sid;
+    private AlgorithmIdentifier     digAlgorithm;
+    private ASN1Set                 authenticatedAttributes;
+    private AlgorithmIdentifier     digEncryptionAlgorithm;
+    private ASN1OctetString         encryptedDigest;
+    private ASN1Set                 unauthenticatedAttributes;
+
+    public static SignerInfo getInstance(
+        Object  o)
+    {
+        if (o == null || o instanceof SignerInfo)
+        {
+            return (SignerInfo)o;
+        }
+        else if (o instanceof ASN1Sequence)
+        {
+            return new SignerInfo((ASN1Sequence)o);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public SignerInfo(
+        SignerIdentifier        sid,
+        AlgorithmIdentifier     digAlgorithm,
+        ASN1Set                 authenticatedAttributes,
+        AlgorithmIdentifier     digEncryptionAlgorithm,
+        ASN1OctetString         encryptedDigest,
+        ASN1Set                 unauthenticatedAttributes)
+    {
+        if (sid.isTagged())
+        {
+            this.version = new DERInteger(3);
+        }
+        else
+        {
+            this.version = new DERInteger(1);
+        }
+
+        this.sid = sid;
+        this.digAlgorithm = digAlgorithm;
+        this.authenticatedAttributes = authenticatedAttributes;
+        this.digEncryptionAlgorithm = digEncryptionAlgorithm;
+        this.encryptedDigest = encryptedDigest;
+        this.unauthenticatedAttributes = unauthenticatedAttributes;
+    }
+
+    public SignerInfo(
+        ASN1Sequence seq)
+    {
+        Enumeration     e = seq.getObjects();
+
+        version = (DERInteger)e.nextElement();
+        sid = SignerIdentifier.getInstance(e.nextElement());
+        digAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement());
+
+        Object obj = e.nextElement();
+
+        if (obj instanceof ASN1TaggedObject)
+        {
+            authenticatedAttributes = ASN1Set.getInstance((ASN1TaggedObject)obj, false);
+
+            digEncryptionAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement());
+        }
+        else
+        {
+            authenticatedAttributes = null;
+            digEncryptionAlgorithm = AlgorithmIdentifier.getInstance(obj);
+        }
+
+        encryptedDigest = DEROctetString.getInstance(e.nextElement());
+
+        if (e.hasMoreElements())
+        {
+            unauthenticatedAttributes = ASN1Set.getInstance((ASN1TaggedObject)e.nextElement(), false);
+        }
+        else
+        {
+            unauthenticatedAttributes = null;
+        }
+    }
+
+    public DERInteger getVersion()
+    {
+        return version;
+    }
+
+    public SignerIdentifier getSID()
+    {
+        return sid;
+    }
+
+    public ASN1Set getAuthenticatedAttributes()
+    {
+        return authenticatedAttributes;
+    }
+
+    public AlgorithmIdentifier getDigestAlgorithm()
+    {
+        return digAlgorithm;
+    }
+
+    public ASN1OctetString getEncryptedDigest()
+    {
+        return encryptedDigest;
+    }
+
+    public AlgorithmIdentifier getDigestEncryptionAlgorithm()
+    {
+        return digEncryptionAlgorithm;
+    }
+
+    public ASN1Set getUnauthenticatedAttributes()
+    {
+        return unauthenticatedAttributes;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  SignerInfo ::= SEQUENCE {
+     *      version Version,
+     *      SignerIdentifier sid,
+     *      digestAlgorithm DigestAlgorithmIdentifier,
+     *      authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
+     *      digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
+     *      encryptedDigest EncryptedDigest,
+     *      unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
+     *  }
+     *
+     *  EncryptedDigest ::= OCTET STRING
+     *
+     *  DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+     *
+     *  DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(version);
+        v.add(sid);
+        v.add(digAlgorithm);
+
+        if (authenticatedAttributes != null)
+        {
+            v.add(new DERTaggedObject(false, 0, authenticatedAttributes));
+        }
+
+        v.add(digEncryptionAlgorithm);
+        v.add(encryptedDigest);
+
+        if (unauthenticatedAttributes != null)
+        {
+            v.add(new DERTaggedObject(false, 1, unauthenticatedAttributes));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cms/Time.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/Time.java
new file mode 100644
index 0000000..6b8817c
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cms/Time.java
@@ -0,0 +1,114 @@
+package org.bouncycastle.asn1.cms;
+
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.SimpleTimeZone;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERGeneralizedTime;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERUTCTime;
+
+public class Time
+    extends ASN1Encodable
+{
+    DERObject   time;
+
+    public static Time getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject());
+    }
+
+    public Time(
+        DERObject   time)
+    {
+        if (!(time instanceof DERUTCTime)
+            && !(time instanceof DERGeneralizedTime))
+        {
+            throw new IllegalArgumentException("unknown object passed to Time");
+        }
+
+        this.time = time; 
+    }
+
+    /**
+     * creates a time object from a given date - if the date is between 1950
+     * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime
+     * is used.
+     */
+    public Time(
+        Date    date)
+    {
+        SimpleTimeZone      tz = new SimpleTimeZone(0, "Z");
+        SimpleDateFormat    dateF = new SimpleDateFormat("yyyyMMddHHmmss");
+
+        dateF.setTimeZone(tz);
+
+        String  d = dateF.format(date) + "Z";
+        int     year = Integer.parseInt(d.substring(0, 4));
+
+        if (year < 1950 || year > 2049)
+        {
+            time = new DERGeneralizedTime(d);
+        }
+        else
+        {
+            time = new DERUTCTime(d.substring(2));
+        }
+    }
+
+    public static Time getInstance(
+        Object  obj)
+    {
+        if (obj instanceof Time)
+        {
+            return (Time)obj;
+        }
+        else if (obj instanceof DERUTCTime)
+        {
+            return new Time((DERUTCTime)obj);
+        }
+        else if (obj instanceof DERGeneralizedTime)
+        {
+            return new Time((DERGeneralizedTime)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public String getTime()
+    {
+        if (time instanceof DERUTCTime)
+        {
+            return ((DERUTCTime)time).getAdjustedTime();
+        }
+        else
+        {
+            return ((DERGeneralizedTime)time).getTime();
+        }
+    }
+
+    public Date getDate()
+    {
+        SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
+
+        return dateF.parse(this.getTime(), new ParsePosition(0));
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * Time ::= CHOICE {
+     *             utcTime        UTCTime,
+     *             generalTime    GeneralizedTime }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        return time;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/cryptopro/CryptoProObjectIdentifiers.java b/libcore/security/src/main/java/org/bouncycastle/asn1/cryptopro/CryptoProObjectIdentifiers.java
new file mode 100644
index 0000000..b5d6c1f
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/cryptopro/CryptoProObjectIdentifiers.java
@@ -0,0 +1,45 @@
+package org.bouncycastle.asn1.cryptopro;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+public interface CryptoProObjectIdentifiers
+{
+    // GOST Algorithms OBJECT IDENTIFIERS :
+    // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2)}
+    static final String                 GOST_id              = "1.2.643.2.2";
+
+    static final DERObjectIdentifier    gostR3411          = new DERObjectIdentifier(GOST_id+".9");
+    
+    static final DERObjectIdentifier    gostR28147_cbc     = new DERObjectIdentifier(GOST_id+".21");
+
+    static final DERObjectIdentifier    gostR3410_94       = new DERObjectIdentifier(GOST_id+".20");
+    static final DERObjectIdentifier    gostR3410_2001     = new DERObjectIdentifier(GOST_id+".19");
+    static final DERObjectIdentifier    gostR3411_94_with_gostR3410_94   = new DERObjectIdentifier(GOST_id+".4");
+    static final DERObjectIdentifier    gostR3411_94_with_gostR3410_2001 = new DERObjectIdentifier(GOST_id+".3");
+
+    // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) hashes(30) }
+    static final DERObjectIdentifier    gostR3411_94_CryptoProParamSet = new DERObjectIdentifier(GOST_id+".30.1");
+
+    // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) signs(32) }
+    static final DERObjectIdentifier    gostR3410_94_CryptoPro_A     = new DERObjectIdentifier(GOST_id+".32.2");
+    static final DERObjectIdentifier    gostR3410_94_CryptoPro_B     = new DERObjectIdentifier(GOST_id+".32.3");
+    static final DERObjectIdentifier    gostR3410_94_CryptoPro_C     = new DERObjectIdentifier(GOST_id+".32.4");
+    static final DERObjectIdentifier    gostR3410_94_CryptoPro_D     = new DERObjectIdentifier(GOST_id+".32.5");
+
+    // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) exchanges(33) }
+    static final DERObjectIdentifier    gostR3410_94_CryptoPro_XchA  = new DERObjectIdentifier(GOST_id+".33.1");
+    static final DERObjectIdentifier    gostR3410_94_CryptoPro_XchB  = new DERObjectIdentifier(GOST_id+".33.2");
+    static final DERObjectIdentifier    gostR3410_94_CryptoPro_XchC  = new DERObjectIdentifier(GOST_id+".33.3");
+
+    //{ iso(1) member-body(2)ru(643) rans(2) cryptopro(2) ecc-signs(35) }
+    static final DERObjectIdentifier    gostR3410_2001_CryptoPro_A = new DERObjectIdentifier(GOST_id+".35.1");
+    static final DERObjectIdentifier    gostR3410_2001_CryptoPro_B = new DERObjectIdentifier(GOST_id+".35.2");
+    static final DERObjectIdentifier    gostR3410_2001_CryptoPro_C = new DERObjectIdentifier(GOST_id+".35.3");
+
+    // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) ecc-exchanges(36) }
+    static final DERObjectIdentifier    gostR3410_2001_CryptoPro_XchA  = new DERObjectIdentifier(GOST_id+".36.0");
+    static final DERObjectIdentifier    gostR3410_2001_CryptoPro_XchB  = new DERObjectIdentifier(GOST_id+".36.1");
+    
+    static final DERObjectIdentifier    gost_ElSgDH3410_default    = new DERObjectIdentifier(GOST_id+".36.0");
+    static final DERObjectIdentifier    gost_ElSgDH3410_1          = new DERObjectIdentifier(GOST_id+".36.1");
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeIdentifier.java b/libcore/security/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeIdentifier.java
new file mode 100644
index 0000000..90e90d4
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeIdentifier.java
@@ -0,0 +1,14 @@
+package org.bouncycastle.asn1.esf;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+
+public interface CommitmentTypeIdentifier
+{
+    public static final DERObjectIdentifier proofOfOrigin = PKCSObjectIdentifiers.id_cti_ets_proofOfOrigin;
+    public static final DERObjectIdentifier proofOfReceipt = PKCSObjectIdentifiers.id_cti_ets_proofOfReceipt;
+    public static final DERObjectIdentifier proofOfDelivery = PKCSObjectIdentifiers.id_cti_ets_proofOfDelivery;
+    public static final DERObjectIdentifier proofOfSender = PKCSObjectIdentifiers.id_cti_ets_proofOfSender;
+    public static final DERObjectIdentifier proofOfApproval = PKCSObjectIdentifiers.id_cti_ets_proofOfApproval;
+    public static final DERObjectIdentifier proofOfCreation = PKCSObjectIdentifiers.id_cti_ets_proofOfCreation;
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeIndication.java b/libcore/security/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeIndication.java
new file mode 100644
index 0000000..76616ea
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeIndication.java
@@ -0,0 +1,83 @@
+package org.bouncycastle.asn1.esf;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+
+public class CommitmentTypeIndication
+    extends ASN1Encodable 
+{
+    private DERObjectIdentifier   commitmentTypeId;
+    private ASN1Sequence          commitmentTypeQualifier;
+    
+    public CommitmentTypeIndication(
+        ASN1Sequence seq)
+    {
+        commitmentTypeId = (DERObjectIdentifier)seq.getObjectAt(0);
+
+        if (seq.size() > 1)
+        {
+            commitmentTypeQualifier = (ASN1Sequence)seq.getObjectAt(1);
+        }
+    }
+
+    public CommitmentTypeIndication(
+        DERObjectIdentifier commitmentTypeId)
+    {
+        this.commitmentTypeId = commitmentTypeId;
+    }
+
+    public CommitmentTypeIndication(
+        DERObjectIdentifier commitmentTypeId,
+        ASN1Sequence        commitmentTypeQualifier)
+    {
+        this.commitmentTypeId = commitmentTypeId;
+        this.commitmentTypeQualifier = commitmentTypeQualifier;
+    }
+
+    public static CommitmentTypeIndication getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof CommitmentTypeIndication)
+        {
+            return (CommitmentTypeIndication)obj;
+        }
+
+        return new CommitmentTypeIndication(ASN1Sequence.getInstance(obj));
+    }
+
+    public DERObjectIdentifier getCommitmentTypeId()
+    {
+        return commitmentTypeId;
+    }
+    
+    public ASN1Sequence getCommitmentTypeQualifier()
+    {
+        return commitmentTypeQualifier;
+    }
+    
+    /**
+     * <pre>
+     * CommitmentTypeIndication ::= SEQUENCE {
+     *      commitmentTypeId   CommitmentTypeIdentifier,
+     *      commitmentTypeQualifier   SEQUENCE SIZE (1..MAX) OF
+     *              CommitmentTypeQualifier OPTIONAL }
+     * </pre>
+     */ 
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+        
+        v.add(commitmentTypeId);
+
+        if (commitmentTypeQualifier != null)
+        {
+            v.add(commitmentTypeQualifier);
+        }
+        
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeQualifier.java b/libcore/security/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeQualifier.java
new file mode 100644
index 0000000..7895e76
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeQualifier.java
@@ -0,0 +1,108 @@
+package org.bouncycastle.asn1.esf;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+
+/**
+ * Commitment type qualifiers, used in the Commitment-Type-Indication attribute (RFC3126).
+ * 
+ * <pre>
+ *   CommitmentTypeQualifier ::= SEQUENCE {
+ *       commitmentTypeIdentifier  CommitmentTypeIdentifier,
+ *       qualifier          ANY DEFINED BY commitmentTypeIdentifier OPTIONAL }
+ * </pre>
+ */
+public class CommitmentTypeQualifier
+    extends ASN1Encodable
+{
+   private DERObjectIdentifier commitmentTypeIdentifier;
+   private DEREncodable qualifier;
+
+   /**
+    * Creates a new <code>CommitmentTypeQualifier</code> instance.
+    *
+    * @param commitmentTypeIdentifier a <code>CommitmentTypeIdentifier</code> value
+    */
+    public CommitmentTypeQualifier(
+        DERObjectIdentifier commitmentTypeIdentifier)
+    {
+        this(commitmentTypeIdentifier, null);
+    }
+    
+   /**
+    * Creates a new <code>CommitmentTypeQualifier</code> instance.
+    *
+    * @param commitmentTypeIdentifier a <code>CommitmentTypeIdentifier</code> value
+    * @param qualifier the qualifier, defined by the above field.
+    */
+    public CommitmentTypeQualifier(
+        DERObjectIdentifier commitmentTypeIdentifier,
+        DEREncodable qualifier) 
+    {
+        this.commitmentTypeIdentifier = commitmentTypeIdentifier;
+        this.qualifier = qualifier;
+    }
+
+    /**
+     * Creates a new <code>CommitmentTypeQualifier</code> instance.
+     *
+     * @param as <code>CommitmentTypeQualifier</code> structure
+     * encoded as an ASN1Sequence. 
+     */
+    public CommitmentTypeQualifier(
+        ASN1Sequence as)
+    {
+        commitmentTypeIdentifier = (DERObjectIdentifier)as.getObjectAt(0);
+        
+        if (as.size() > 1)
+        {
+            qualifier = as.getObjectAt(1);
+        }
+    }
+
+    public static CommitmentTypeQualifier getInstance(Object as)
+    {
+        if (as instanceof CommitmentTypeQualifier || as == null)
+        {
+            return (CommitmentTypeQualifier)as;
+        }
+        else if (as instanceof ASN1Sequence)
+        {
+            return new CommitmentTypeQualifier((ASN1Sequence)as);
+        }
+
+        throw new IllegalArgumentException("unknown object in getInstance.");
+    }
+
+    public DERObjectIdentifier getCommitmentTypeIdentifier()
+    {
+        return commitmentTypeIdentifier;
+    }
+    
+    public DEREncodable getQualifier()
+    {
+        return qualifier;
+    }
+
+   /**
+    * Returns a DER-encodable representation of this instance. 
+    *
+    * @return a <code>DERObject</code> value
+    */
+   public DERObject toASN1Object() 
+   {
+      ASN1EncodableVector dev = new ASN1EncodableVector();
+      dev.add(commitmentTypeIdentifier);
+      if (qualifier != null)
+      {
+          dev.add(qualifier);
+      }
+
+      return new DERSequence(dev);
+   }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/esf/ESFAttributes.java b/libcore/security/src/main/java/org/bouncycastle/asn1/esf/ESFAttributes.java
new file mode 100644
index 0000000..6d652e0
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/esf/ESFAttributes.java
@@ -0,0 +1,11 @@
+package org.bouncycastle.asn1.esf;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+
+public interface ESFAttributes
+{
+    public static final DERObjectIdentifier  sigPolicyId = PKCSObjectIdentifiers.id_aa_sigPolicyId;
+    public static final DERObjectIdentifier  commitmentType = PKCSObjectIdentifiers.id_aa_commitmentType;
+    public static final DERObjectIdentifier  signerLocation = PKCSObjectIdentifiers.id_aa_signerLocation;
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/esf/SignerLocation.java b/libcore/security/src/main/java/org/bouncycastle/asn1/esf/SignerLocation.java
new file mode 100644
index 0000000..49bd819
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/esf/SignerLocation.java
@@ -0,0 +1,146 @@
+package org.bouncycastle.asn1.esf;
+
+import org.bouncycastle.asn1.*;
+
+import java.util.Enumeration;
+
+/**
+ * Signer-Location attribute (RFC3126).
+ * 
+ * <pre>
+ *   SignerLocation ::= SEQUENCE {
+ *       countryName        [0] DirectoryString OPTIONAL,
+ *       localityName       [1] DirectoryString OPTIONAL,
+ *       postalAddress      [2] PostalAddress OPTIONAL }
+ *
+ *   PostalAddress ::= SEQUENCE SIZE(1..6) OF DirectoryString
+ * </pre>
+ */
+public class SignerLocation
+    extends ASN1Encodable 
+{
+    private DERUTF8String   countryName;
+    private DERUTF8String   localityName;
+    private ASN1Sequence    postalAddress;
+    
+    public SignerLocation(
+        ASN1Sequence seq)
+    {
+        Enumeration     e = seq.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            DERTaggedObject o = (DERTaggedObject)e.nextElement();
+
+            switch (o.getTagNo())
+            {
+            case 0:
+                this.countryName = DERUTF8String.getInstance(o, true);
+                break;
+            case 1:
+                this.localityName = DERUTF8String.getInstance(o, true);
+                break;
+            case 2:
+                this.postalAddress = ASN1Sequence.getInstance(o, true);
+                if (postalAddress != null && postalAddress.size() > 6)
+                {
+                    throw new IllegalArgumentException("postal address must contain less than 6 strings");
+                }
+                break;
+            default:
+                throw new IllegalArgumentException("illegal tag");
+            }
+        }
+    }
+
+    public SignerLocation(
+        DERUTF8String   countryName,
+        DERUTF8String   localityName,
+        ASN1Sequence    postalAddress)
+    {
+        if (postalAddress != null && postalAddress.size() > 6)
+        {
+            throw new IllegalArgumentException("postal address must contain less than 6 strings");
+        }
+
+        if (countryName != null)
+        {
+            this.countryName = DERUTF8String.getInstance(countryName.toASN1Object());
+        }
+
+        if (localityName != null)
+        {
+            this.localityName = DERUTF8String.getInstance(localityName.toASN1Object());
+        }
+
+        if (postalAddress != null)
+        {
+            this.postalAddress = ASN1Sequence.getInstance(postalAddress.toASN1Object());
+        }
+    }
+
+    public static SignerLocation getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof SignerLocation)
+        {
+            return (SignerLocation)obj;
+        }
+
+        return new SignerLocation(ASN1Sequence.getInstance(obj));
+    }
+
+    public DERUTF8String getCountryName()
+    {
+        return countryName;
+    }
+
+    public DERUTF8String getLocalityName()
+    {
+        return localityName;
+    }
+
+    public ASN1Sequence getPostalAddress()
+    {
+        return postalAddress;
+    }
+
+    /**
+     * <pre>
+     *   SignerLocation ::= SEQUENCE {
+     *       countryName        [0] DirectoryString OPTIONAL,
+     *       localityName       [1] DirectoryString OPTIONAL,
+     *       postalAddress      [2] PostalAddress OPTIONAL }
+     *
+     *   PostalAddress ::= SEQUENCE SIZE(1..6) OF DirectoryString
+     *   
+     *   DirectoryString ::= CHOICE {
+     *         teletexString           TeletexString (SIZE (1..MAX)),
+     *         printableString         PrintableString (SIZE (1..MAX)),
+     *         universalString         UniversalString (SIZE (1..MAX)),
+     *         utf8String              UTF8String (SIZE (1.. MAX)),
+     *         bmpString               BMPString (SIZE (1..MAX)) }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        if (countryName != null)
+        {
+            v.add(new DERTaggedObject(true, 0, countryName));
+        }
+
+        if (localityName != null)
+        {
+            v.add(new DERTaggedObject(true, 1, localityName));
+        }
+
+        if (postalAddress != null)
+        {
+            v.add(new DERTaggedObject(true, 2, postalAddress));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ess/ContentIdentifier.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ess/ContentIdentifier.java
new file mode 100644
index 0000000..88b4f45
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ess/ContentIdentifier.java
@@ -0,0 +1,65 @@
+package org.bouncycastle.asn1.ess;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DEROctetString;
+
+public class ContentIdentifier
+    extends ASN1Encodable
+{
+     ASN1OctetString value;
+
+    public static ContentIdentifier getInstance(Object o)
+    {
+        if (o == null || o instanceof ContentIdentifier)
+        {
+            return (ContentIdentifier) o;
+        }
+        else if (o instanceof ASN1OctetString)
+        {
+            return new ContentIdentifier((ASN1OctetString) o);
+        }
+
+        throw new IllegalArgumentException(
+                "unknown object in 'ContentIdentifier' factory : "
+                        + o.getClass().getName() + ".");
+    }
+
+    /**
+     * Create from OCTET STRING whose octets represent the identifier.
+     */
+    public ContentIdentifier(
+        ASN1OctetString value)
+    {
+        this.value = value;
+    }
+
+    /**
+     * Create from byte array representing the identifier.
+     */
+    public ContentIdentifier(
+        byte[] value)
+    {
+        this(new DEROctetString(value));
+    }
+    
+    public ASN1OctetString getValue()
+    {
+        return value;
+    }
+
+    /**
+     * The definition of ContentIdentifier is
+     * <pre>
+     * ContentIdentifier ::=  OCTET STRING
+     * </pre>
+     * id-aa-contentIdentifier OBJECT IDENTIFIER ::= { iso(1)
+     *  member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
+     *  smime(16) id-aa(2) 7 }
+     */
+    public DERObject toASN1Object()
+    {
+        return value;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ess/ESSCertID.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ess/ESSCertID.java
new file mode 100644
index 0000000..69b107a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ess/ESSCertID.java
@@ -0,0 +1,97 @@
+package org.bouncycastle.asn1.ess;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.IssuerSerial;
+
+public class ESSCertID
+    extends ASN1Encodable
+{
+    private ASN1OctetString certHash;
+
+    private IssuerSerial issuerSerial;
+
+    public static ESSCertID getInstance(Object o)
+    {
+        if (o == null || o instanceof ESSCertID)
+        {
+            return (ESSCertID)o;
+        }
+        else if (o instanceof ASN1Sequence)
+        {
+            return new ESSCertID((ASN1Sequence)o);
+        }
+
+        throw new IllegalArgumentException(
+                "unknown object in 'ESSCertID' factory : "
+                        + o.getClass().getName() + ".");
+    }
+
+    /**
+     * constructor
+     */
+    public ESSCertID(ASN1Sequence seq)
+    {
+        if (seq.size() < 1 || seq.size() > 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+        }
+
+        certHash = ASN1OctetString.getInstance(seq.getObjectAt(0));
+ 
+        if (seq.size() > 1)
+        {
+            issuerSerial = IssuerSerial.getInstance(seq.getObjectAt(1));
+        }
+    }
+
+    public ESSCertID(
+        byte[]          hash)
+    {
+        certHash = new DEROctetString(hash);
+    }
+
+    public ESSCertID(
+        byte[]          hash,
+        IssuerSerial    issuerSerial)
+    {
+        this.certHash = new DEROctetString(hash);
+        this.issuerSerial = issuerSerial;
+    }
+
+    public byte[] getCertHash()
+    {
+        return certHash.getOctets();
+    }
+
+    public IssuerSerial getIssuerSerial()
+    {
+        return issuerSerial;
+    }
+
+    /**
+     * <pre>
+     * ESSCertID ::= SEQUENCE {
+     *     certHash Hash, 
+     *     issuerSerial IssuerSerial OPTIONAL }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+        
+        v.add(certHash);
+        
+        if (issuerSerial != null)
+        {
+            v.add(issuerSerial);
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ess/OtherCertID.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ess/OtherCertID.java
new file mode 100644
index 0000000..dcd5d50
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ess/OtherCertID.java
@@ -0,0 +1,138 @@
+package org.bouncycastle.asn1.ess;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.IssuerSerial;
+import org.bouncycastle.asn1.x509.DigestInfo;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class OtherCertID
+    extends ASN1Encodable
+{
+    private ASN1Encodable otherCertHash;
+    private IssuerSerial issuerSerial;
+
+    public static OtherCertID getInstance(Object o)
+    {
+        if (o == null || o instanceof OtherCertID)
+        {
+            return (OtherCertID) o;
+        }
+        else if (o instanceof ASN1Sequence)
+        {
+            return new OtherCertID((ASN1Sequence) o);
+        }
+
+        throw new IllegalArgumentException(
+                "unknown object in 'OtherCertID' factory : "
+                        + o.getClass().getName() + ".");
+    }
+
+    /**
+     * constructor
+     */
+    public OtherCertID(ASN1Sequence seq)
+    {
+        if (seq.size() < 1 || seq.size() > 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + seq.size());
+        }
+
+        if (seq.getObjectAt(0).getDERObject() instanceof ASN1OctetString)
+        {
+            otherCertHash = ASN1OctetString.getInstance(seq.getObjectAt(0));
+        }
+        else
+        {
+            otherCertHash = DigestInfo.getInstance(seq.getObjectAt(0));
+
+        }
+
+        if (seq.size() > 1)
+        {
+            issuerSerial = new IssuerSerial(ASN1Sequence.getInstance(seq.getObjectAt(1)));
+        }
+    }
+
+    public OtherCertID(
+        AlgorithmIdentifier  algId,
+        byte[]               digest)
+    {
+        this.otherCertHash = new DigestInfo(algId, digest);
+    }
+
+    public OtherCertID(
+        AlgorithmIdentifier  algId,
+        byte[]               digest,
+        IssuerSerial    issuerSerial)
+    {
+        this.otherCertHash = new DigestInfo(algId, digest);
+        this.issuerSerial = issuerSerial;
+    }
+
+    public AlgorithmIdentifier getAlgorithmHash()
+    {
+        if (otherCertHash.getDERObject() instanceof ASN1OctetString)
+        {
+            // SHA-1
+            return new AlgorithmIdentifier("1.3.14.3.2.26");
+        }
+        else
+        {
+            return DigestInfo.getInstance(otherCertHash).getAlgorithmId();
+        }
+    }
+
+    public byte[] getCertHash()
+    {
+        if (otherCertHash.getDERObject() instanceof ASN1OctetString)
+        {
+            // SHA-1
+            return ((ASN1OctetString)otherCertHash.getDERObject()).getOctets();
+        }
+        else
+        {
+            return DigestInfo.getInstance(otherCertHash).getDigest();
+        }
+    }
+
+    public IssuerSerial getIssuerSerial()
+    {
+        return issuerSerial;
+    }
+
+    /**
+     * <pre>
+     * OtherCertID ::= SEQUENCE {
+     *     otherCertHash    OtherHash,
+     *     issuerSerial     IssuerSerial OPTIONAL }
+     *
+     * OtherHash ::= CHOICE {
+     *     sha1Hash     OCTET STRING,
+     *     otherHash    OtherHashAlgAndValue }
+     *
+     * OtherHashAlgAndValue ::= SEQUENCE {
+     *     hashAlgorithm    AlgorithmIdentifier,
+     *     hashValue        OCTET STRING }
+     *
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(otherCertHash);
+
+        if (issuerSerial != null)
+        {
+            v.add(issuerSerial);
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ess/OtherSigningCertificate.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ess/OtherSigningCertificate.java
new file mode 100644
index 0000000..4bc12a4
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ess/OtherSigningCertificate.java
@@ -0,0 +1,111 @@
+package org.bouncycastle.asn1.ess;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.PolicyInformation;
+
+public class OtherSigningCertificate
+    extends ASN1Encodable
+{
+    ASN1Sequence certs;
+    ASN1Sequence policies;
+
+    public static OtherSigningCertificate getInstance(Object o)
+    {
+        if (o == null || o instanceof OtherSigningCertificate)
+        {
+            return (OtherSigningCertificate) o;
+        }
+        else if (o instanceof ASN1Sequence)
+        {
+            return new OtherSigningCertificate((ASN1Sequence) o);
+        }
+
+        throw new IllegalArgumentException(
+                "unknown object in 'OtherSigningCertificate' factory : "
+                        + o.getClass().getName() + ".");
+    }
+
+    /**
+     * constructeurs
+     */
+    public OtherSigningCertificate(ASN1Sequence seq)
+    {
+        if (seq.size() < 1 || seq.size() > 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + seq.size());
+        }
+
+        this.certs = ASN1Sequence.getInstance(seq.getObjectAt(0));
+
+        if (seq.size() > 1)
+        {
+            this.policies = ASN1Sequence.getInstance(seq.getObjectAt(1));
+        }
+    }
+
+    public OtherSigningCertificate(
+        OtherCertID otherCertID)
+    {
+        certs = new DERSequence(otherCertID);
+    }
+
+    public OtherCertID[] getCerts()
+    {
+        OtherCertID[] cs = new OtherCertID[certs.size()];
+
+        for (int i = 0; i != certs.size(); i++)
+        {
+            cs[i] = OtherCertID.getInstance(certs.getObjectAt(i));
+        }
+
+        return cs;
+    }
+
+    public PolicyInformation[] getPolicies()
+    {
+        if (policies == null)
+        {
+            return null;
+        }
+
+        PolicyInformation[] ps = new PolicyInformation[policies.size()];
+
+        for (int i = 0; i != policies.size(); i++)
+        {
+            ps[i] = PolicyInformation.getInstance(policies.getObjectAt(i));
+        }
+
+        return ps;
+    }
+
+    /**
+     * The definition of OtherSigningCertificate is
+     * <pre>
+     * OtherSigningCertificate ::=  SEQUENCE {
+     *      certs        SEQUENCE OF OtherCertID,
+     *      policies     SEQUENCE OF PolicyInformation OPTIONAL
+     * }
+     * </pre>
+     * id-aa-otherSigCert OBJECT IDENTIFIER ::= { iso(1)
+     *  member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
+     *  smime(16) id-aa(2) 19 }
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(certs);
+
+        if (policies != null)
+        {
+            v.add(policies);
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ess/SigningCertificate.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ess/SigningCertificate.java
new file mode 100644
index 0000000..bd3c904
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ess/SigningCertificate.java
@@ -0,0 +1,111 @@
+package org.bouncycastle.asn1.ess;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.PolicyInformation;
+
+
+public class SigningCertificate
+    extends ASN1Encodable
+{
+    ASN1Sequence certs;
+    ASN1Sequence policies;
+
+    public static SigningCertificate getInstance(Object o)
+    {
+        if (o == null || o instanceof SigningCertificate)
+        {
+            return (SigningCertificate) o;
+        }
+        else if (o instanceof ASN1Sequence)
+        {
+            return new SigningCertificate((ASN1Sequence) o);
+        }
+
+        throw new IllegalArgumentException(
+                "unknown object in 'SigningCertificate' factory : "
+                        + o.getClass().getName() + ".");
+    }
+
+    /**
+     * constructeurs
+     */
+    public SigningCertificate(ASN1Sequence seq)
+    {
+        if (seq.size() < 1 || seq.size() > 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + seq.size());
+        }
+        this.certs = ASN1Sequence.getInstance(seq.getObjectAt(0));
+        
+        if (seq.size() > 1)
+        {
+            this.policies = ASN1Sequence.getInstance(seq.getObjectAt(1));
+        }
+    }
+
+    public SigningCertificate(
+        ESSCertID essCertID)
+    {
+        certs = new DERSequence(essCertID);
+    }
+
+    public ESSCertID[] getCerts()
+    {
+        ESSCertID[] cs = new ESSCertID[certs.size()];
+        
+        for (int i = 0; i != certs.size(); i++)
+        {
+            cs[i] = ESSCertID.getInstance(certs.getObjectAt(i));
+        }
+        
+        return cs;
+    }
+    
+    public PolicyInformation[] getPolicies()
+    {
+        if (policies == null)
+        {
+            return null;
+        }
+        
+        PolicyInformation[] ps = new PolicyInformation[policies.size()];
+        
+        for (int i = 0; i != policies.size(); i++)
+        {
+            ps[i] = PolicyInformation.getInstance(policies.getObjectAt(i));
+        }
+        
+        return ps;
+    }
+    
+    /**
+     * The definition of SigningCertificate is
+     * <pre>
+     * SigningCertificate ::=  SEQUENCE {
+     *      certs        SEQUENCE OF ESSCertID,
+     *      policies     SEQUENCE OF PolicyInformation OPTIONAL
+     * }
+     * </pre>
+     * id-aa-signingCertificate OBJECT IDENTIFIER ::= { iso(1)
+     *  member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
+     *  smime(16) id-aa(2) 12 }
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(certs);
+        
+        if (policies != null)
+        {
+            v.add(policies);
+        }
+        
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/gnu/GNUObjectIdentifiers.java b/libcore/security/src/main/java/org/bouncycastle/asn1/gnu/GNUObjectIdentifiers.java
new file mode 100644
index 0000000..d375f90
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/gnu/GNUObjectIdentifiers.java
@@ -0,0 +1,30 @@
+package org.bouncycastle.asn1.gnu;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+public interface GNUObjectIdentifiers
+{
+    public static final DERObjectIdentifier GNU = new DERObjectIdentifier("1.3.6.1.4.1.11591.1"); // GNU Radius
+    public static final DERObjectIdentifier GnuPG = new DERObjectIdentifier("1.3.6.1.4.1.11591.2"); // GnuPG (Aegypten)
+    public static final DERObjectIdentifier notation = new DERObjectIdentifier("1.3.6.1.4.1.11591.2.1"); // notation
+    public static final DERObjectIdentifier pkaAddress = new DERObjectIdentifier("1.3.6.1.4.1.11591.2.1.1"); // pkaAddress
+    public static final DERObjectIdentifier GnuRadar = new DERObjectIdentifier("1.3.6.1.4.1.11591.3"); // GNU Radar
+    public static final DERObjectIdentifier digestAlgorithm = new DERObjectIdentifier("1.3.6.1.4.1.11591.12"); // digestAlgorithm
+    public static final DERObjectIdentifier Tiger_192 = new DERObjectIdentifier("1.3.6.1.4.1.11591.12.2"); // TIGER/192
+    public static final DERObjectIdentifier encryptionAlgorithm = new DERObjectIdentifier("1.3.6.1.4.1.11591.13"); // encryptionAlgorithm
+    public static final DERObjectIdentifier Serpent = new DERObjectIdentifier("1.3.6.1.4.1.11591.13.2"); // Serpent
+    public static final DERObjectIdentifier Serpent_128_ECB = new DERObjectIdentifier("1.3.6.1.4.1.11591.13.2.1"); // Serpent-128-ECB
+    public static final DERObjectIdentifier Serpent_128_CBC = new DERObjectIdentifier("1.3.6.1.4.1.11591.13.2.2"); // Serpent-128-CBC
+    public static final DERObjectIdentifier Serpent_128_OFB = new DERObjectIdentifier("1.3.6.1.4.1.11591.13.2.3"); // Serpent-128-OFB
+    public static final DERObjectIdentifier Serpent_128_CFB = new DERObjectIdentifier("1.3.6.1.4.1.11591.13.2.4"); // Serpent-128-CFB
+    public static final DERObjectIdentifier Serpent_192_ECB = new DERObjectIdentifier("1.3.6.1.4.1.11591.13.2.21"); // Serpent-192-ECB
+    public static final DERObjectIdentifier Serpent_192_CBC = new DERObjectIdentifier("1.3.6.1.4.1.11591.13.2.22"); // Serpent-192-CBC
+    public static final DERObjectIdentifier Serpent_192_OFB = new DERObjectIdentifier("1.3.6.1.4.1.11591.13.2.23"); // Serpent-192-OFB
+    public static final DERObjectIdentifier Serpent_192_CFB = new DERObjectIdentifier("1.3.6.1.4.1.11591.13.2.24"); // Serpent-192-CFB
+    public static final DERObjectIdentifier Serpent_256_ECB = new DERObjectIdentifier("1.3.6.1.4.1.11591.13.2.41"); // Serpent-256-ECB
+    public static final DERObjectIdentifier Serpent_256_CBC = new DERObjectIdentifier("1.3.6.1.4.1.11591.13.2.42"); // Serpent-256-CBC
+    public static final DERObjectIdentifier Serpent_256_OFB = new DERObjectIdentifier("1.3.6.1.4.1.11591.13.2.43"); // Serpent-256-OFB
+    public static final DERObjectIdentifier Serpent_256_CFB = new DERObjectIdentifier("1.3.6.1.4.1.11591.13.2.44"); // Serpent-256-CFB
+    public static final DERObjectIdentifier CRC = new DERObjectIdentifier("1.3.6.1.4.1.11591.14"); // CRC algorithms
+    public static final DERObjectIdentifier CRC32 = new DERObjectIdentifier("1.3.6.1.4.1.11591.14.1"); // CRC 32
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java b/libcore/security/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java
new file mode 100644
index 0000000..6faa597
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java
@@ -0,0 +1,20 @@
+package org.bouncycastle.asn1.iana;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+public interface IANAObjectIdentifiers
+{
+    // id-SHA1 OBJECT IDENTIFIER ::=    
+    // {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) ipsec(8) isakmpOakley(1)}
+    //
+
+    static final DERObjectIdentifier    isakmpOakley  = new DERObjectIdentifier("1.3.6.1.5.5.8.1");
+
+    static final DERObjectIdentifier    hmacMD5       = new DERObjectIdentifier(isakmpOakley + ".1");
+    static final DERObjectIdentifier    hmacSHA1     = new DERObjectIdentifier(isakmpOakley + ".2");
+    
+    static final DERObjectIdentifier    hmacTIGER     = new DERObjectIdentifier(isakmpOakley + ".3");
+    
+    static final DERObjectIdentifier    hmacRIPEMD160 = new DERObjectIdentifier(isakmpOakley + ".4");
+
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/icao/DataGroupHash.java b/libcore/security/src/main/java/org/bouncycastle/asn1/icao/DataGroupHash.java
new file mode 100644
index 0000000..3413126
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/icao/DataGroupHash.java
@@ -0,0 +1,100 @@
+package org.bouncycastle.asn1.icao;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+/**
+ * The DataGroupHash object.
+ * <pre>
+ * DataGroupHash  ::=  SEQUENCE {
+ *      dataGroupNumber         DataGroupNumber,
+ *      dataGroupHashValue     OCTET STRING }
+ * 
+ * DataGroupNumber ::= INTEGER {
+ *         dataGroup1    (1),
+ *         dataGroup1    (2),
+ *         dataGroup1    (3),
+ *         dataGroup1    (4),
+ *         dataGroup1    (5),
+ *         dataGroup1    (6),
+ *         dataGroup1    (7),
+ *         dataGroup1    (8),
+ *         dataGroup1    (9),
+ *         dataGroup1    (10),
+ *         dataGroup1    (11),
+ *         dataGroup1    (12),
+ *         dataGroup1    (13),
+ *         dataGroup1    (14),
+ *         dataGroup1    (15),
+ *         dataGroup1    (16) }
+ * 
+ * </pre>
+ */
+public class DataGroupHash 
+    extends ASN1Encodable
+{
+    DERInteger dataGroupNumber;    
+    ASN1OctetString    dataGroupHashValue;
+    
+    public static DataGroupHash getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof DataGroupHash)
+        {
+            return (DataGroupHash)obj;
+        }
+
+        if (obj instanceof ASN1Sequence)
+        {
+            return new DataGroupHash(ASN1Sequence.getInstance(obj));            
+        }
+        else
+        {
+            throw new IllegalArgumentException("unknown object in getInstance");
+        }
+    }                
+            
+    public DataGroupHash(ASN1Sequence seq)
+    {
+        Enumeration e = seq.getObjects();
+
+        // dataGroupNumber
+        dataGroupNumber = DERInteger.getInstance(e.nextElement());
+        // dataGroupHashValue
+        dataGroupHashValue = ASN1OctetString.getInstance(e.nextElement());   
+    }
+    
+    public DataGroupHash(
+        int dataGroupNumber,        
+        ASN1OctetString     dataGroupHashValue)
+    {
+        this.dataGroupNumber = new DERInteger(dataGroupNumber);
+        this.dataGroupHashValue = dataGroupHashValue; 
+    }    
+
+    public int getDataGroupNumber()
+    {
+        return dataGroupNumber.getValue().intValue();
+    }
+    
+    public ASN1OctetString getDataGroupHashValue()
+    {
+        return dataGroupHashValue;
+    }     
+    
+    public DERObject toASN1Object() 
+    {
+        ASN1EncodableVector seq = new ASN1EncodableVector();
+        seq.add(dataGroupNumber);
+        seq.add(dataGroupHashValue);  
+
+        return new DERSequence(seq);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/icao/ICAOObjectIdentifiers.java b/libcore/security/src/main/java/org/bouncycastle/asn1/icao/ICAOObjectIdentifiers.java
new file mode 100644
index 0000000..957993a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/icao/ICAOObjectIdentifiers.java
@@ -0,0 +1,15 @@
+package org.bouncycastle.asn1.icao;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+public interface ICAOObjectIdentifiers
+{
+    //
+    // base id
+    //
+    static final String                 id_icao                   = "1.3.27";
+
+    static final DERObjectIdentifier    id_icao_mrtd              = new DERObjectIdentifier(id_icao+".1");
+    static final DERObjectIdentifier    id_icao_mrtd_security     = new DERObjectIdentifier(id_icao_mrtd+".1");
+    static final DERObjectIdentifier    id_icao_ldsSecurityObject = new DERObjectIdentifier(id_icao_mrtd_security+".1");
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/icao/LDSSecurityObject.java b/libcore/security/src/main/java/org/bouncycastle/asn1/icao/LDSSecurityObject.java
new file mode 100644
index 0000000..177fdcf
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/icao/LDSSecurityObject.java
@@ -0,0 +1,125 @@
+package org.bouncycastle.asn1.icao;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * The LDSSecurityObject object.
+ * <pre>
+ * LDSSecurityObject ::= SEQUENCE {
+ *   version                LDSSecurityObjectVersion,
+ *   hashAlgorithm          DigestAlgorithmIdentifier,
+ *   dataGroupHashValues    SEQUENCE SIZE (2..ub-DataGroups) OF DataHashGroup}
+ *   
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier,
+ * 
+ * LDSSecurityObjectVersion :: INTEGER {V0(0)}
+ * </pre>
+ */
+
+public class LDSSecurityObject 
+    extends ASN1Encodable 
+    implements ICAOObjectIdentifiers    
+{
+    
+    public static final int ub_DataGroups = 16;
+    
+    DERInteger version = new DERInteger(0);
+    AlgorithmIdentifier digestAlgorithmIdentifier; 
+    DataGroupHash[] datagroupHash;            
+
+    public static LDSSecurityObject getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof LDSSecurityObject)
+        {
+            return (LDSSecurityObject)obj;
+        }
+
+        if (obj instanceof ASN1Sequence)
+        {
+            return new LDSSecurityObject(ASN1Sequence.getInstance(obj));            
+        }
+        
+        throw new IllegalArgumentException("unknown object in getInstance");
+    }    
+    
+    public LDSSecurityObject(
+        ASN1Sequence seq)
+    {
+        if (seq == null || seq.size() == 0)
+        {
+            throw new IllegalArgumentException("null or empty sequence passed.");
+        }
+        
+        Enumeration e = seq.getObjects();
+
+        // version
+        version = DERInteger.getInstance(e.nextElement());
+        // digestAlgorithmIdentifier
+        digestAlgorithmIdentifier = AlgorithmIdentifier.getInstance(e.nextElement());
+      
+        ASN1Sequence datagroupHashSeq = ASN1Sequence.getInstance(e.nextElement());
+
+        checkDatagroupHashSeqSize(datagroupHashSeq.size());        
+        
+        datagroupHash = new DataGroupHash[datagroupHashSeq.size()];
+        for (int i= 0; i< datagroupHashSeq.size();i++)
+        {
+            datagroupHash[i] = DataGroupHash.getInstance(datagroupHashSeq.getObjectAt(i));
+        } 
+        
+    }
+
+    public LDSSecurityObject(
+        AlgorithmIdentifier digestAlgorithmIdentifier, 
+        DataGroupHash[]       datagroupHash)
+    {
+        this.digestAlgorithmIdentifier = digestAlgorithmIdentifier;
+        this.datagroupHash = datagroupHash;
+        
+        checkDatagroupHashSeqSize(datagroupHash.length);                      
+    }    
+        
+    private void checkDatagroupHashSeqSize(int size)
+    {
+        if ((size < 2) || (size > ub_DataGroups))
+        {
+               throw new IllegalArgumentException("wrong size in DataGroupHashValues : not in (2.."+ ub_DataGroups +")");
+        }
+    }  
+    
+    public AlgorithmIdentifier getDigestAlgorithmIdentifier()
+    {
+        return digestAlgorithmIdentifier;
+    }
+    
+    public DataGroupHash[] getDatagroupHash()
+    {
+        return datagroupHash;
+    }
+
+    public DERObject toASN1Object() 
+    {
+        ASN1EncodableVector seq = new ASN1EncodableVector();
+        
+        seq.add(version);
+        seq.add(digestAlgorithmIdentifier);
+                
+        ASN1EncodableVector seqname = new ASN1EncodableVector();
+        for (int i = 0; i < datagroupHash.length; i++) 
+        {
+            seqname.add(datagroupHash[i]);
+        }            
+        seq.add(new DERSequence(seqname));                   
+        
+        return new DERSequence(seq);
+    }          
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/misc/IDEACBCPar.java b/libcore/security/src/main/java/org/bouncycastle/asn1/misc/IDEACBCPar.java
new file mode 100644
index 0000000..c384e8a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/misc/IDEACBCPar.java
@@ -0,0 +1,75 @@
+package org.bouncycastle.asn1.misc;
+
+import org.bouncycastle.asn1.*;
+
+public class IDEACBCPar
+    extends ASN1Encodable
+{
+    ASN1OctetString  iv;
+
+    public static IDEACBCPar getInstance(
+        Object  o)
+    {
+        if (o instanceof IDEACBCPar)
+        {
+            return (IDEACBCPar)o;
+        }
+        else if (o instanceof ASN1Sequence)
+        {
+            return new IDEACBCPar((ASN1Sequence)o);
+        }
+
+        throw new IllegalArgumentException("unknown object in IDEACBCPar factory");
+    }
+
+    public IDEACBCPar(
+        byte[]  iv)
+    {
+        this.iv = new DEROctetString(iv);
+    }
+
+    public IDEACBCPar(
+        ASN1Sequence  seq)
+    {
+        if (seq.size() == 1)
+        {
+            iv = (ASN1OctetString)seq.getObjectAt(0);
+        }
+        else
+        {
+            iv = null;
+        }
+    }
+
+    public byte[] getIV()
+    {
+        if (iv != null)
+        {
+            return iv.getOctets();
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * IDEA-CBCPar ::= SEQUENCE {
+     *                      iv    OCTET STRING OPTIONAL -- exactly 8 octets
+     *                  }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        if (iv != null)
+        {
+            v.add(iv);
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java b/libcore/security/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java
new file mode 100644
index 0000000..b2d46e2
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java
@@ -0,0 +1,30 @@
+package org.bouncycastle.asn1.misc;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+public interface MiscObjectIdentifiers
+{
+    //
+    // Netscape
+    //       iso/itu(2) joint-assign(16) us(840) uscompany(1) netscape(113730) cert-extensions(1) }
+    //
+    static final String                 netscape                = "2.16.840.1.113730.1";
+    static final DERObjectIdentifier    netscapeCertType        = new DERObjectIdentifier(netscape + ".1");
+    static final DERObjectIdentifier    netscapeBaseURL         = new DERObjectIdentifier(netscape + ".2");
+    static final DERObjectIdentifier    netscapeRevocationURL   = new DERObjectIdentifier(netscape + ".3");
+    static final DERObjectIdentifier    netscapeCARevocationURL = new DERObjectIdentifier(netscape + ".4");
+    static final DERObjectIdentifier    netscapeRenewalURL      = new DERObjectIdentifier(netscape + ".7");
+    static final DERObjectIdentifier    netscapeCApolicyURL     = new DERObjectIdentifier(netscape + ".8");
+    static final DERObjectIdentifier    netscapeSSLServerName   = new DERObjectIdentifier(netscape + ".12");
+    static final DERObjectIdentifier    netscapeCertComment     = new DERObjectIdentifier(netscape + ".13");
+    //
+    // Verisign
+    //       iso/itu(2) joint-assign(16) us(840) uscompany(1) verisign(113733) cert-extensions(1) }
+    //
+    static final String                 verisign                = "2.16.840.1.113733.1";
+
+    //
+    // CZAG - country, zip, age, and gender
+    //
+    static final DERObjectIdentifier    verisignCzagExtension   = new DERObjectIdentifier(verisign + ".6.3");
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/misc/NetscapeCertType.java b/libcore/security/src/main/java/org/bouncycastle/asn1/misc/NetscapeCertType.java
new file mode 100644
index 0000000..61a851a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/misc/NetscapeCertType.java
@@ -0,0 +1,54 @@
+package org.bouncycastle.asn1.misc;
+
+import org.bouncycastle.asn1.*;
+
+/**
+ * The NetscapeCertType object.
+ * <pre>
+ *    NetscapeCertType ::= BIT STRING {
+ *         SSLClient               (0),
+ *         SSLServer               (1),
+ *         S/MIME                  (2),
+ *         Object Signing          (3),
+ *         Reserved                (4),
+ *         SSL CA                  (5),
+ *         S/MIME CA               (6),
+ *         Object Signing CA       (7) }
+ * </pre>
+ */
+public class NetscapeCertType
+    extends DERBitString
+{
+    public static final int        sslClient        = (1 << 7); 
+    public static final int        sslServer        = (1 << 6);
+    public static final int        smime            = (1 << 5);
+    public static final int        objectSigning    = (1 << 4);
+    public static final int        reserved         = (1 << 3);
+    public static final int        sslCA            = (1 << 2);
+    public static final int        smimeCA          = (1 << 1);
+    public static final int        objectSigningCA  = (1 << 0);
+
+    /**
+     * Basic constructor.
+     * 
+     * @param usage - the bitwise OR of the Key Usage flags giving the
+     * allowed uses for the key.
+     * e.g. (X509NetscapeCertType.sslCA | X509NetscapeCertType.smimeCA)
+     */
+    public NetscapeCertType(
+        int usage)
+    {
+        super(getBytes(usage), getPadBits(usage));
+    }
+
+    public NetscapeCertType(
+        DERBitString usage)
+    {
+        super(usage.getBytes(), usage.getPadBits());
+    }
+
+    public String toString()
+    {
+        return "NetscapeCertType: 0x" + Integer.toHexString(data[0] & 0xff);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/misc/NetscapeRevocationURL.java b/libcore/security/src/main/java/org/bouncycastle/asn1/misc/NetscapeRevocationURL.java
new file mode 100644
index 0000000..ba35d08
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/misc/NetscapeRevocationURL.java
@@ -0,0 +1,18 @@
+package org.bouncycastle.asn1.misc;
+
+import org.bouncycastle.asn1.*;
+
+public class NetscapeRevocationURL
+    extends DERIA5String
+{
+    public NetscapeRevocationURL(
+        DERIA5String str)
+    {
+        super(str.getString());
+    }
+
+    public String toString()
+    {
+        return "NetscapeRevocationURL: " + this.getString();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/misc/VerisignCzagExtension.java b/libcore/security/src/main/java/org/bouncycastle/asn1/misc/VerisignCzagExtension.java
new file mode 100644
index 0000000..5066ec5
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/misc/VerisignCzagExtension.java
@@ -0,0 +1,18 @@
+package org.bouncycastle.asn1.misc;
+
+import org.bouncycastle.asn1.*;
+
+public class VerisignCzagExtension
+    extends DERIA5String
+{
+    public VerisignCzagExtension(
+        DERIA5String str)
+    {
+        super(str.getString());
+    }
+
+    public String toString()
+    {
+        return "VerisignCzagExtension: " + this.getString();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/mozilla/PublicKeyAndChallenge.java b/libcore/security/src/main/java/org/bouncycastle/asn1/mozilla/PublicKeyAndChallenge.java
new file mode 100644
index 0000000..57df8b0
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/mozilla/PublicKeyAndChallenge.java
@@ -0,0 +1,63 @@
+package org.bouncycastle.asn1.mozilla;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERIA5String;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+
+/**
+ * This is designed to parse
+ * the PublicKeyAndChallenge created by the KEYGEN tag included by
+ * Mozilla based browsers.
+ *  <pre>
+ *  PublicKeyAndChallenge ::= SEQUENCE {
+ *    spki SubjectPublicKeyInfo,
+ *    challenge IA5STRING
+ *  }
+ *
+ *  </pre>
+ */
+public class PublicKeyAndChallenge
+    extends ASN1Encodable
+{
+    private ASN1Sequence         pkacSeq;
+    private SubjectPublicKeyInfo spki;
+    private DERIA5String         challenge;
+
+    public static PublicKeyAndChallenge getInstance(Object obj)
+    {
+        if (obj instanceof PublicKeyAndChallenge)
+        {
+            return (PublicKeyAndChallenge)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new PublicKeyAndChallenge((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unkown object in factory");
+    }
+
+    public PublicKeyAndChallenge(ASN1Sequence seq)
+    {
+        pkacSeq = seq;
+        spki = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(0));
+        challenge = DERIA5String.getInstance(seq.getObjectAt(1));
+    }
+
+    public DERObject toASN1Object()
+    {
+        return pkacSeq;
+    }
+
+    public SubjectPublicKeyInfo getSubjectPublicKeyInfo()
+    {
+        return spki;
+    }
+
+    public DERIA5String getChallenge()
+    {
+        return challenge;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java b/libcore/security/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java
new file mode 100644
index 0000000..e4a2777
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java
@@ -0,0 +1,48 @@
+package org.bouncycastle.asn1.nist;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+public interface NISTObjectIdentifiers
+{
+    //
+    // NIST
+    //     iso/itu(2) joint-assign(16) us(840) organization(1) gov(101) csor(3) 
+
+    //
+    // nistalgorithms(4)
+    //
+    static final String                 nistAlgorithm          = "2.16.840.1.101.3.4";
+
+    static final DERObjectIdentifier    id_sha256               = new DERObjectIdentifier(nistAlgorithm + ".2.1");
+    static final DERObjectIdentifier    id_sha384               = new DERObjectIdentifier(nistAlgorithm + ".2.2");
+    static final DERObjectIdentifier    id_sha512               = new DERObjectIdentifier(nistAlgorithm + ".2.3");
+    static final DERObjectIdentifier    id_sha224               = new DERObjectIdentifier(nistAlgorithm + ".2.4");
+    
+    static final String                 aes                     = nistAlgorithm + ".1";
+    
+    static final DERObjectIdentifier    id_aes128_ECB           = new DERObjectIdentifier(aes + ".1"); 
+    static final DERObjectIdentifier    id_aes128_CBC           = new DERObjectIdentifier(aes + ".2");
+    static final DERObjectIdentifier    id_aes128_OFB           = new DERObjectIdentifier(aes + ".3"); 
+    static final DERObjectIdentifier    id_aes128_CFB           = new DERObjectIdentifier(aes + ".4"); 
+    static final DERObjectIdentifier    id_aes128_wrap          = new DERObjectIdentifier(aes + ".5");
+    
+    static final DERObjectIdentifier    id_aes192_ECB           = new DERObjectIdentifier(aes + ".21"); 
+    static final DERObjectIdentifier    id_aes192_CBC           = new DERObjectIdentifier(aes + ".22"); 
+    static final DERObjectIdentifier    id_aes192_OFB           = new DERObjectIdentifier(aes + ".23"); 
+    static final DERObjectIdentifier    id_aes192_CFB           = new DERObjectIdentifier(aes + ".24"); 
+    static final DERObjectIdentifier    id_aes192_wrap          = new DERObjectIdentifier(aes + ".25");
+    
+    static final DERObjectIdentifier    id_aes256_ECB           = new DERObjectIdentifier(aes + ".41"); 
+    static final DERObjectIdentifier    id_aes256_CBC           = new DERObjectIdentifier(aes + ".42");
+    static final DERObjectIdentifier    id_aes256_OFB           = new DERObjectIdentifier(aes + ".43"); 
+    static final DERObjectIdentifier    id_aes256_CFB           = new DERObjectIdentifier(aes + ".44"); 
+    static final DERObjectIdentifier    id_aes256_wrap          = new DERObjectIdentifier(aes + ".45"); 
+
+    //
+    // signatures
+    //
+    static final DERObjectIdentifier    id_dsa_with_sha2        = new DERObjectIdentifier(nistAlgorithm + ".3"); 
+
+    static final DERObjectIdentifier    dsa_with_sha224         = new DERObjectIdentifier(id_dsa_with_sha2 + ".1"); 
+    static final DERObjectIdentifier    dsa_with_sha256         = new DERObjectIdentifier(id_dsa_with_sha2 + ".2"); 
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/BasicOCSPResponse.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/BasicOCSPResponse.java
new file mode 100644
index 0000000..c78e193
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/BasicOCSPResponse.java
@@ -0,0 +1,112 @@
+package org.bouncycastle.asn1.ocsp;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class BasicOCSPResponse
+    extends ASN1Encodable
+{
+    private ResponseData        tbsResponseData;
+    private AlgorithmIdentifier signatureAlgorithm;
+    private DERBitString        signature;
+    private ASN1Sequence        certs;
+
+    public BasicOCSPResponse(
+        ResponseData        tbsResponseData,
+        AlgorithmIdentifier signatureAlgorithm,
+        DERBitString        signature,
+        ASN1Sequence        certs)
+    {
+        this.tbsResponseData = tbsResponseData;
+        this.signatureAlgorithm = signatureAlgorithm;
+        this.signature = signature;
+        this.certs = certs;
+    }
+
+    public BasicOCSPResponse(
+        ASN1Sequence    seq)
+    {
+        this.tbsResponseData = ResponseData.getInstance(seq.getObjectAt(0));
+        this.signatureAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
+        this.signature = (DERBitString)seq.getObjectAt(2);
+
+        if (seq.size() > 3)
+        {
+            this.certs = ASN1Sequence.getInstance((ASN1TaggedObject)seq.getObjectAt(3), true);
+        }
+    }
+
+    public static BasicOCSPResponse getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static BasicOCSPResponse getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof BasicOCSPResponse)
+        {
+            return (BasicOCSPResponse)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new BasicOCSPResponse((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public ResponseData getTbsResponseData()
+    {
+        return tbsResponseData;
+    }
+
+    public AlgorithmIdentifier getSignatureAlgorithm()
+    {
+        return signatureAlgorithm;
+    }
+
+    public DERBitString getSignature()
+    {
+        return signature;
+    }
+
+    public ASN1Sequence getCerts()
+    {
+        return certs;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * BasicOCSPResponse       ::= SEQUENCE {
+     *      tbsResponseData      ResponseData,
+     *      signatureAlgorithm   AlgorithmIdentifier,
+     *      signature            BIT STRING,
+     *      certs                [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(tbsResponseData);
+        v.add(signatureAlgorithm);
+        v.add(signature);
+        if (certs != null)
+        {
+            v.add(new DERTaggedObject(true, 0, certs));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/CertID.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/CertID.java
new file mode 100644
index 0000000..2f5fe85
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/CertID.java
@@ -0,0 +1,105 @@
+package org.bouncycastle.asn1.ocsp;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class CertID
+    extends ASN1Encodable
+{
+    AlgorithmIdentifier    hashAlgorithm;
+    ASN1OctetString        issuerNameHash;
+    ASN1OctetString        issuerKeyHash;
+    DERInteger             serialNumber;
+
+    public CertID(
+        AlgorithmIdentifier hashAlgorithm,
+        ASN1OctetString     issuerNameHash,
+        ASN1OctetString     issuerKeyHash,
+        DERInteger          serialNumber)
+    {
+        this.hashAlgorithm = hashAlgorithm;
+        this.issuerNameHash = issuerNameHash;
+        this.issuerKeyHash = issuerKeyHash;
+        this.serialNumber = serialNumber;
+    }
+
+    public CertID(
+        ASN1Sequence    seq)
+    {
+        hashAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0));
+        issuerNameHash = (ASN1OctetString)seq.getObjectAt(1);
+        issuerKeyHash = (ASN1OctetString)seq.getObjectAt(2);
+        serialNumber = (DERInteger)seq.getObjectAt(3);
+    }
+
+    public static CertID getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static CertID getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof CertID)
+        {
+            return (CertID)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new CertID((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public AlgorithmIdentifier getHashAlgorithm()
+    {
+        return hashAlgorithm;
+    }
+
+    public ASN1OctetString getIssuerNameHash()
+    {
+        return issuerNameHash;
+    }
+
+    public ASN1OctetString getIssuerKeyHash()
+    {
+        return issuerKeyHash;
+    }
+
+    public DERInteger getSerialNumber()
+    {
+        return serialNumber;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * CertID          ::=     SEQUENCE {
+     *     hashAlgorithm       AlgorithmIdentifier,
+     *     issuerNameHash      OCTET STRING, -- Hash of Issuer's DN
+     *     issuerKeyHash       OCTET STRING, -- Hash of Issuers public key
+     *     serialNumber        CertificateSerialNumber }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector    v = new ASN1EncodableVector();
+
+        v.add(hashAlgorithm);
+        v.add(issuerNameHash);
+        v.add(issuerKeyHash);
+        v.add(serialNumber);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java
new file mode 100644
index 0000000..1868bfc
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java
@@ -0,0 +1,111 @@
+package org.bouncycastle.asn1.ocsp;
+
+import org.bouncycastle.asn1.ASN1Choice;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+public class CertStatus
+    extends ASN1Encodable
+    implements ASN1Choice
+{
+    private int             tagNo;
+    private DEREncodable    value;
+
+    /**
+     * create a CertStatus object with a tag of zero.
+     */
+    public CertStatus()
+    {
+        tagNo = 0;
+        // BEGIN android-changed
+        value = DERNull.THE_ONE;
+        // END android-changed
+    }
+
+    public CertStatus(
+        RevokedInfo info)
+    {
+        tagNo = 1;
+        value = info;
+    }
+
+    public CertStatus(
+        int tagNo,
+        DEREncodable    value)
+    {
+        this.tagNo = tagNo;
+        this.value = value;
+    }
+
+    public CertStatus(
+        ASN1TaggedObject    choice)
+    {
+        this.tagNo = choice.getTagNo();
+
+        switch (choice.getTagNo())
+        {
+        case 0:
+            // BEGIN android-changed
+            value = DERNull.THE_ONE;
+            // END android-changed
+            break;
+        case 1:
+            value = RevokedInfo.getInstance(choice, false);
+            break;
+        case 2:
+            // BEGIN android-changed
+            value = DERNull.THE_ONE;
+            // END android-changed
+        }
+    }
+
+    public static CertStatus getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof CertStatus)
+        {
+            return (CertStatus)obj;
+        }
+        else if (obj instanceof ASN1TaggedObject)
+        {
+            return new CertStatus((ASN1TaggedObject)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public static CertStatus getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject()); // must be explicitly tagged
+    }
+    
+    public int getTagNo()
+    {
+        return tagNo;
+    }
+
+    public DEREncodable getStatus()
+    {
+        return value;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  CertStatus ::= CHOICE {
+     *                  good        [0]     IMPLICIT NULL,
+     *                  revoked     [1]     IMPLICIT RevokedInfo,
+     *                  unknown     [2]     IMPLICIT UnknownInfo }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        return new DERTaggedObject(false, tagNo, value);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/CrlID.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/CrlID.java
new file mode 100644
index 0000000..c933ac0
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/CrlID.java
@@ -0,0 +1,86 @@
+package org.bouncycastle.asn1.ocsp;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.*;
+
+public class CrlID
+    extends ASN1Encodable
+{
+    DERIA5String        crlUrl;
+    DERInteger          crlNum;
+    DERGeneralizedTime  crlTime;
+
+    public CrlID(
+        ASN1Sequence    seq)
+    {
+        Enumeration    e = seq.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            ASN1TaggedObject    o = (ASN1TaggedObject)e.nextElement();
+
+            switch (o.getTagNo())
+            {
+            case 0:
+                crlUrl = DERIA5String.getInstance(o, true);
+                break;
+            case 1:
+                crlNum = DERInteger.getInstance(o, true);
+                break;
+            case 2:
+                crlTime = DERGeneralizedTime.getInstance(o, true);
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "unknown tag number: " + o.getTagNo());
+            }
+        }
+    }
+
+    public DERIA5String getCrlUrl()
+    {
+        return crlUrl;
+    }
+
+    public DERInteger getCrlNum()
+    {
+        return crlNum;
+    }
+
+    public DERGeneralizedTime getCrlTime()
+    {
+        return crlTime;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * CrlID ::= SEQUENCE {
+     *     crlUrl               [0]     EXPLICIT IA5String OPTIONAL,
+     *     crlNum               [1]     EXPLICIT INTEGER OPTIONAL,
+     *     crlTime              [2]     EXPLICIT GeneralizedTime OPTIONAL }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector    v = new ASN1EncodableVector();
+
+        if (crlUrl != null)
+        {
+            v.add(new DERTaggedObject(true, 0, crlUrl));
+        }
+
+        if (crlNum != null)
+        {
+            v.add(new DERTaggedObject(true, 1, crlNum));
+        }
+
+        if (crlTime != null)
+        {
+            v.add(new DERTaggedObject(true, 2, crlTime));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/OCSPObjectIdentifiers.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/OCSPObjectIdentifiers.java
new file mode 100644
index 0000000..f247270
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/OCSPObjectIdentifiers.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.asn1.ocsp;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+public interface OCSPObjectIdentifiers
+{
+    public static final String pkix_ocsp = "1.3.6.1.5.5.7.48.1";
+
+    public static final DERObjectIdentifier id_pkix_ocsp = new DERObjectIdentifier(pkix_ocsp);
+    public static final DERObjectIdentifier id_pkix_ocsp_basic = new DERObjectIdentifier(pkix_ocsp + ".1");
+    
+    //
+    // extensions
+    //
+    public static final DERObjectIdentifier id_pkix_ocsp_nonce = new DERObjectIdentifier(pkix_ocsp + ".2");
+    public static final DERObjectIdentifier id_pkix_ocsp_crl = new DERObjectIdentifier(pkix_ocsp + ".3");
+    
+    public static final DERObjectIdentifier id_pkix_ocsp_response = new DERObjectIdentifier(pkix_ocsp + ".4");
+    public static final DERObjectIdentifier id_pkix_ocsp_nocheck = new DERObjectIdentifier(pkix_ocsp + ".5");
+    public static final DERObjectIdentifier id_pkix_ocsp_archive_cutoff = new DERObjectIdentifier(pkix_ocsp + ".6");
+    public static final DERObjectIdentifier id_pkix_ocsp_service_locator = new DERObjectIdentifier(pkix_ocsp + ".7");
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/OCSPRequest.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/OCSPRequest.java
new file mode 100644
index 0000000..3f379de
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/OCSPRequest.java
@@ -0,0 +1,90 @@
+package org.bouncycastle.asn1.ocsp;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+public class OCSPRequest
+    extends ASN1Encodable
+{
+    TBSRequest      tbsRequest;
+    Signature       optionalSignature;
+
+    public OCSPRequest(
+        TBSRequest  tbsRequest,
+        Signature   optionalSignature)
+    {
+        this.tbsRequest = tbsRequest;
+        this.optionalSignature = optionalSignature;
+    }
+
+    public OCSPRequest(
+        ASN1Sequence    seq)
+    {
+        tbsRequest = TBSRequest.getInstance(seq.getObjectAt(0));
+
+        if (seq.size() == 2)
+        {
+            optionalSignature = Signature.getInstance(
+                                (ASN1TaggedObject)seq.getObjectAt(1), true);
+        }
+    }
+    
+    public static OCSPRequest getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static OCSPRequest getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof OCSPRequest)
+        {
+            return (OCSPRequest)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new OCSPRequest((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+    
+    public TBSRequest getTbsRequest()
+    {
+        return tbsRequest;
+    }
+
+    public Signature getOptionalSignature()
+    {
+        return optionalSignature;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * OCSPRequest     ::=     SEQUENCE {
+     *     tbsRequest                  TBSRequest,
+     *     optionalSignature   [0]     EXPLICIT Signature OPTIONAL }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector    v = new ASN1EncodableVector();
+
+        v.add(tbsRequest);
+
+        if (optionalSignature != null)
+        {
+            v.add(new DERTaggedObject(true, 0, optionalSignature));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/OCSPResponse.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/OCSPResponse.java
new file mode 100644
index 0000000..9fbf740
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/OCSPResponse.java
@@ -0,0 +1,92 @@
+package org.bouncycastle.asn1.ocsp;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DEREnumerated;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+public class OCSPResponse
+    extends ASN1Encodable
+{
+    OCSPResponseStatus    responseStatus;
+    ResponseBytes        responseBytes;
+
+    public OCSPResponse(
+        OCSPResponseStatus  responseStatus,
+        ResponseBytes       responseBytes)
+    {
+        this.responseStatus = responseStatus;
+        this.responseBytes = responseBytes;
+    }
+
+    public OCSPResponse(
+        ASN1Sequence    seq)
+    {
+        responseStatus = new OCSPResponseStatus(
+                            DEREnumerated.getInstance(seq.getObjectAt(0)));
+
+        if (seq.size() == 2)
+        {
+            responseBytes = ResponseBytes.getInstance(
+                                (ASN1TaggedObject)seq.getObjectAt(1), true);
+        }
+    }
+
+    public static OCSPResponse getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static OCSPResponse getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof OCSPResponse)
+        {
+            return (OCSPResponse)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new OCSPResponse((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public OCSPResponseStatus getResponseStatus()
+    {
+        return responseStatus;
+    }
+
+    public ResponseBytes getResponseBytes()
+    {
+        return responseBytes;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * OCSPResponse ::= SEQUENCE {
+     *     responseStatus         OCSPResponseStatus,
+     *     responseBytes          [0] EXPLICIT ResponseBytes OPTIONAL }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector    v = new ASN1EncodableVector();
+
+        v.add(responseStatus);
+
+        if (responseBytes != null)
+        {
+            v.add(new DERTaggedObject(true, 0, responseBytes));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/OCSPResponseStatus.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/OCSPResponseStatus.java
new file mode 100644
index 0000000..7185235
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/OCSPResponseStatus.java
@@ -0,0 +1,40 @@
+package org.bouncycastle.asn1.ocsp;
+
+import org.bouncycastle.asn1.DEREnumerated;
+
+public class OCSPResponseStatus
+    extends DEREnumerated
+{
+    public static final int SUCCESSFUL = 0;
+    public static final int MALFORMED_REQUEST = 1;
+    public static final int INTERNAL_ERROR = 2;
+    public static final int TRY_LATER = 3;
+    public static final int SIG_REQUIRED = 5;
+    public static final int UNAUTHORIZED = 6;
+
+    /**
+     * The OCSPResponseStatus enumeration.
+     * <pre>
+     * OCSPResponseStatus ::= ENUMERATED {
+     *     successful            (0),  --Response has valid confirmations
+     *     malformedRequest      (1),  --Illegal confirmation request
+     *     internalError         (2),  --Internal error in issuer
+     *     tryLater              (3),  --Try again later
+     *                                 --(4) is not used
+     *     sigRequired           (5),  --Must sign the request
+     *     unauthorized          (6)   --Request unauthorized
+     * }
+     * </pre>
+     */
+    public OCSPResponseStatus(
+        int value)
+    {
+        super(value);
+    }
+
+    public OCSPResponseStatus(
+        DEREnumerated value)
+    {
+        super(value.getValue().intValue());
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/Request.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/Request.java
new file mode 100644
index 0000000..350fa17
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/Request.java
@@ -0,0 +1,91 @@
+package org.bouncycastle.asn1.ocsp;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x509.X509Extensions;
+
+public class Request
+    extends ASN1Encodable
+{
+    CertID            reqCert;
+    X509Extensions    singleRequestExtensions;
+
+    public Request(
+        CertID          reqCert,
+        X509Extensions  singleRequestExtensions)
+    {
+        this.reqCert = reqCert;
+        this.singleRequestExtensions = singleRequestExtensions;
+    }
+
+    public Request(
+        ASN1Sequence    seq)
+    {
+        reqCert = CertID.getInstance(seq.getObjectAt(0));
+
+        if (seq.size() == 2)
+        {
+            singleRequestExtensions = X509Extensions.getInstance(
+                                (ASN1TaggedObject)seq.getObjectAt(1), true);
+        }
+    }
+
+    public static Request getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static Request getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof Request)
+        {
+            return (Request)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new Request((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public CertID getReqCert()
+    {
+        return reqCert;
+    }
+
+    public X509Extensions getSingleRequestExtensions()
+    {
+        return singleRequestExtensions;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * Request         ::=     SEQUENCE {
+     *     reqCert                     CertID,
+     *     singleRequestExtensions     [0] EXPLICIT Extensions OPTIONAL }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector    v = new ASN1EncodableVector();
+
+        v.add(reqCert);
+
+        if (singleRequestExtensions != null)
+        {
+            v.add(new DERTaggedObject(true, 0, singleRequestExtensions));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/ResponderID.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/ResponderID.java
new file mode 100644
index 0000000..09cdf11
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/ResponderID.java
@@ -0,0 +1,83 @@
+package org.bouncycastle.asn1.ocsp;
+
+import org.bouncycastle.asn1.ASN1Choice;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x509.X509Name;
+
+public class ResponderID
+    extends ASN1Encodable
+    implements ASN1Choice
+{
+    private DEREncodable    value;
+
+    public ResponderID(
+        ASN1OctetString    value)
+    {
+        this.value = value;
+    }
+
+    public ResponderID(
+        X509Name    value)
+    {
+        this.value = value;
+    }
+
+    public static ResponderID getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof ResponderID)
+        {
+            return (ResponderID)obj;
+        }
+        else if (obj instanceof DEROctetString)
+        {
+            return new ResponderID((DEROctetString)obj);
+        }
+        else if (obj instanceof ASN1TaggedObject)
+        {
+            ASN1TaggedObject    o = (ASN1TaggedObject)obj;
+
+            if (o.getTagNo() == 1)
+            {
+                return new ResponderID(X509Name.getInstance(o, true));
+            }
+            else
+            {
+                return new ResponderID(ASN1OctetString.getInstance(o, true));
+            }
+        }
+
+        return new ResponderID(X509Name.getInstance(obj));
+    }
+
+    public static ResponderID getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject()); // must be explicitly tagged
+    }
+    
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * ResponderID ::= CHOICE {
+     *      byName          [1] Name,
+     *      byKey           [2] KeyHash }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        if (value instanceof ASN1OctetString)
+        {
+            return new DERTaggedObject(true, 2, value);
+        }
+
+        return new DERTaggedObject(true, 1, value);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/ResponseBytes.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/ResponseBytes.java
new file mode 100644
index 0000000..997f41f
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/ResponseBytes.java
@@ -0,0 +1,82 @@
+package org.bouncycastle.asn1.ocsp;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+
+public class ResponseBytes
+    extends ASN1Encodable
+{
+    DERObjectIdentifier    responseType;
+    ASN1OctetString        response;
+
+    public ResponseBytes(
+        DERObjectIdentifier responseType,
+        ASN1OctetString     response)
+    {
+        this.responseType = responseType;
+        this.response = response;
+    }
+
+    public ResponseBytes(
+        ASN1Sequence    seq)
+    {
+        responseType = (DERObjectIdentifier)seq.getObjectAt(0);
+        response = (ASN1OctetString)seq.getObjectAt(1);
+    }
+
+    public static ResponseBytes getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static ResponseBytes getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof ResponseBytes)
+        {
+            return (ResponseBytes)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new ResponseBytes((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public DERObjectIdentifier getResponseType()
+    {
+        return responseType;
+    }
+
+    public ASN1OctetString getResponse()
+    {
+        return response;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * ResponseBytes ::=       SEQUENCE {
+     *     responseType   OBJECT IDENTIFIER,
+     *     response       OCTET STRING }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector    v = new ASN1EncodableVector();
+
+        v.add(responseType);
+        v.add(response);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/ResponseData.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/ResponseData.java
new file mode 100644
index 0000000..db0e586
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/ResponseData.java
@@ -0,0 +1,164 @@
+package org.bouncycastle.asn1.ocsp;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DERGeneralizedTime;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x509.X509Extensions;
+
+public class ResponseData
+    extends ASN1Encodable
+{
+    private static final DERInteger V1 = new DERInteger(0);
+    
+    private boolean             versionPresent;
+    
+    private DERInteger          version;
+    private ResponderID         responderID;
+    private DERGeneralizedTime  producedAt;
+    private ASN1Sequence        responses;
+    private X509Extensions      responseExtensions;
+
+    public ResponseData(
+        DERInteger          version,
+        ResponderID         responderID,
+        DERGeneralizedTime  producedAt,
+        ASN1Sequence        responses,
+        X509Extensions      responseExtensions)
+    {
+        this.version = version;
+        this.responderID = responderID;
+        this.producedAt = producedAt;
+        this.responses = responses;
+        this.responseExtensions = responseExtensions;
+    }
+    
+    public ResponseData(
+        ResponderID         responderID,
+        DERGeneralizedTime  producedAt,
+        ASN1Sequence        responses,
+        X509Extensions      responseExtensions)
+    {
+        this(V1, responderID, producedAt, responses, responseExtensions);
+    }
+    
+    public ResponseData(
+        ASN1Sequence    seq)
+    {
+        int index = 0;
+
+        if (seq.getObjectAt(0) instanceof ASN1TaggedObject)
+        {
+            ASN1TaggedObject    o = (ASN1TaggedObject)seq.getObjectAt(0);
+
+            if (o.getTagNo() == 0)
+            {
+                this.versionPresent = true;
+                this.version = DERInteger.getInstance(
+                                (ASN1TaggedObject)seq.getObjectAt(0), true);
+                index++;
+            }
+            else
+            {
+                this.version = V1;
+            }
+        }
+        else
+        {
+            this.version = V1;
+        }
+
+        this.responderID = ResponderID.getInstance(seq.getObjectAt(index++));
+        this.producedAt = (DERGeneralizedTime)seq.getObjectAt(index++);
+        this.responses = (ASN1Sequence)seq.getObjectAt(index++);
+
+        if (seq.size() > index)
+        {
+            this.responseExtensions = X509Extensions.getInstance(
+                                (ASN1TaggedObject)seq.getObjectAt(index), true);
+        }
+    }
+
+    public static ResponseData getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static ResponseData getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof ResponseData)
+        {
+            return (ResponseData)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new ResponseData((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public DERInteger getVersion()
+    {
+        return version;
+    }
+
+    public ResponderID getResponderID()
+    {
+        return responderID;
+    }
+
+    public DERGeneralizedTime getProducedAt()
+    {
+        return producedAt;
+    }
+
+    public ASN1Sequence getResponses()
+    {
+        return responses;
+    }
+
+    public X509Extensions getResponseExtensions()
+    {
+        return responseExtensions;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * ResponseData ::= SEQUENCE {
+     *     version              [0] EXPLICIT Version DEFAULT v1,
+     *     responderID              ResponderID,
+     *     producedAt               GeneralizedTime,
+     *     responses                SEQUENCE OF SingleResponse,
+     *     responseExtensions   [1] EXPLICIT Extensions OPTIONAL }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        if (versionPresent || !version.equals(V1))
+        {
+            v.add(new DERTaggedObject(true, 0, version));
+        }
+
+        v.add(responderID);
+        v.add(producedAt);
+        v.add(responses);
+        if (responseExtensions != null)
+        {
+            v.add(new DERTaggedObject(true, 1, responseExtensions));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/RevokedInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/RevokedInfo.java
new file mode 100644
index 0000000..501a117
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/RevokedInfo.java
@@ -0,0 +1,92 @@
+package org.bouncycastle.asn1.ocsp;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DEREnumerated;
+import org.bouncycastle.asn1.DERGeneralizedTime;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x509.CRLReason;
+
+public class RevokedInfo
+    extends ASN1Encodable
+{
+    private DERGeneralizedTime  revocationTime;
+    private CRLReason           revocationReason;
+
+    public RevokedInfo(
+        DERGeneralizedTime  revocationTime,
+        CRLReason           revocationReason)
+    {
+        this.revocationTime = revocationTime;
+        this.revocationReason = revocationReason;
+    }
+
+    public RevokedInfo(
+        ASN1Sequence    seq)
+    {
+        this.revocationTime = (DERGeneralizedTime)seq.getObjectAt(0);
+
+        if (seq.size() > 1)
+        {
+            this.revocationReason = new CRLReason(DEREnumerated.getInstance(
+                                (ASN1TaggedObject)seq.getObjectAt(1), true));
+        }
+    }
+
+    public static RevokedInfo getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static RevokedInfo getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof RevokedInfo)
+        {
+            return (RevokedInfo)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new RevokedInfo((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public DERGeneralizedTime getRevocationTime()
+    {
+        return revocationTime;
+    }
+
+    public CRLReason getRevocationReason()
+    {
+        return revocationReason;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * RevokedInfo ::= SEQUENCE {
+     *      revocationTime              GeneralizedTime,
+     *      revocationReason    [0]     EXPLICIT CRLReason OPTIONAL }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(revocationTime);
+        if (revocationReason != null)
+        {
+            v.add(new DERTaggedObject(true, 0, revocationReason));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/ServiceLocator.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/ServiceLocator.java
new file mode 100644
index 0000000..296dd53
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/ServiceLocator.java
@@ -0,0 +1,36 @@
+package org.bouncycastle.asn1.ocsp;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.X509Name;
+
+public class ServiceLocator
+    extends ASN1Encodable
+{
+    X509Name    issuer;
+    DERObject    locator;
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * ServiceLocator ::= SEQUENCE {
+     *     issuer    Name,
+     *     locator   AuthorityInfoAccessSyntax OPTIONAL }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector    v = new ASN1EncodableVector();
+
+        v.add(issuer);
+
+        if (locator != null)
+        {
+            v.add(locator);
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/Signature.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/Signature.java
new file mode 100644
index 0000000..907fd9b
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/Signature.java
@@ -0,0 +1,111 @@
+package org.bouncycastle.asn1.ocsp;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class Signature
+    extends ASN1Encodable
+{
+    AlgorithmIdentifier signatureAlgorithm;
+    DERBitString        signature;
+    ASN1Sequence        certs;
+
+    public Signature(
+        AlgorithmIdentifier signatureAlgorithm,
+        DERBitString        signature)
+    {
+        this.signatureAlgorithm = signatureAlgorithm;
+        this.signature = signature;
+    }
+
+    public Signature(
+        AlgorithmIdentifier signatureAlgorithm,
+        DERBitString        signature,
+        ASN1Sequence        certs)
+    {
+        this.signatureAlgorithm = signatureAlgorithm;
+        this.signature = signature;
+        this.certs = certs;
+    }
+
+    public Signature(
+        ASN1Sequence    seq)
+    {
+        signatureAlgorithm  = AlgorithmIdentifier.getInstance(seq.getObjectAt(0));
+        signature = (DERBitString)seq.getObjectAt(1);
+
+        if (seq.size() == 3)
+        {
+            certs = ASN1Sequence.getInstance(
+                                (ASN1TaggedObject)seq.getObjectAt(2), true);
+        }
+    }
+
+    public static Signature getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static Signature getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof Signature)
+        {
+            return (Signature)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new Signature((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public AlgorithmIdentifier getSignatureAlgorithm()
+    {
+        return signatureAlgorithm;
+    }
+
+    public DERBitString getSignature()
+    {
+        return signature;
+    }
+
+    public ASN1Sequence getCerts()
+    {
+        return certs;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * Signature       ::=     SEQUENCE {
+     *     signatureAlgorithm      AlgorithmIdentifier,
+     *     signature               BIT STRING,
+     *     certs               [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL}
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector    v = new ASN1EncodableVector();
+
+        v.add(signatureAlgorithm);
+        v.add(signature);
+
+        if (certs != null)
+        {
+            v.add(new DERTaggedObject(true, 0, certs));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/SingleResponse.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/SingleResponse.java
new file mode 100644
index 0000000..a16f14b
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/SingleResponse.java
@@ -0,0 +1,143 @@
+package org.bouncycastle.asn1.ocsp;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERGeneralizedTime;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x509.X509Extensions;
+
+public class SingleResponse
+    extends ASN1Encodable
+{
+    private CertID              certID;
+    private CertStatus          certStatus;
+    private DERGeneralizedTime  thisUpdate;
+    private DERGeneralizedTime  nextUpdate;
+    private X509Extensions      singleExtensions;
+
+    public SingleResponse(
+        CertID              certID,
+        CertStatus          certStatus,
+        DERGeneralizedTime  thisUpdate,
+        DERGeneralizedTime  nextUpdate,
+        X509Extensions      singleExtensions)
+    {
+        this.certID = certID;
+        this.certStatus = certStatus;
+        this.thisUpdate = thisUpdate;
+        this.nextUpdate = nextUpdate;
+        this.singleExtensions = singleExtensions;
+    }
+
+    public SingleResponse(
+        ASN1Sequence    seq)
+    {
+        this.certID = CertID.getInstance(seq.getObjectAt(0));
+        this.certStatus = CertStatus.getInstance(seq.getObjectAt(1));
+        this.thisUpdate = (DERGeneralizedTime)seq.getObjectAt(2);
+
+        if (seq.size() > 4)
+        {
+            this.nextUpdate = DERGeneralizedTime.getInstance(
+                                (ASN1TaggedObject)seq.getObjectAt(3), true);
+            this.singleExtensions = X509Extensions.getInstance(
+                                (ASN1TaggedObject)seq.getObjectAt(4), true);
+        }
+        else if (seq.size() > 3)
+        {
+            ASN1TaggedObject    o = (ASN1TaggedObject)seq.getObjectAt(3);
+
+            if (o.getTagNo() == 0)
+            {
+                this.nextUpdate = DERGeneralizedTime.getInstance(o, true);
+            }
+            else
+            {
+                this.singleExtensions = X509Extensions.getInstance(o, true);
+            }
+        }
+    }
+
+    public static SingleResponse getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static SingleResponse getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof SingleResponse)
+        {
+            return (SingleResponse)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new SingleResponse((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public CertID getCertID()
+    {
+        return certID;
+    }
+
+    public CertStatus getCertStatus()
+    {
+        return certStatus;
+    }
+
+    public DERGeneralizedTime getThisUpdate()
+    {
+        return thisUpdate;
+    }
+
+    public DERGeneralizedTime getNextUpdate()
+    {
+        return nextUpdate;
+    }
+
+    public X509Extensions getSingleExtensions()
+    {
+        return singleExtensions;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  SingleResponse ::= SEQUENCE {
+     *          certID                       CertID,
+     *          certStatus                   CertStatus,
+     *          thisUpdate                   GeneralizedTime,
+     *          nextUpdate         [0]       EXPLICIT GeneralizedTime OPTIONAL,
+     *          singleExtensions   [1]       EXPLICIT Extensions OPTIONAL }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(certID);
+        v.add(certStatus);
+        v.add(thisUpdate);
+
+        if (nextUpdate != null)
+        {
+            v.add(new DERTaggedObject(true, 0, nextUpdate));
+        }
+
+        if (singleExtensions != null)
+        {
+            v.add(new DERTaggedObject(true, 1, singleExtensions));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/TBSRequest.java b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/TBSRequest.java
new file mode 100644
index 0000000..fd4e86b
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/ocsp/TBSRequest.java
@@ -0,0 +1,150 @@
+package org.bouncycastle.asn1.ocsp;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.X509Extensions;
+
+public class TBSRequest
+    extends ASN1Encodable
+{
+    private static final DERInteger V1 = new DERInteger(0);
+    
+    DERInteger      version;
+    GeneralName     requestorName;
+    ASN1Sequence    requestList;
+    X509Extensions  requestExtensions;
+
+    public TBSRequest(
+        GeneralName     requestorName,
+        ASN1Sequence    requestList,
+        X509Extensions  requestExtensions)
+    {
+        this.version = V1;
+        this.requestorName = requestorName;
+        this.requestList = requestList;
+        this.requestExtensions = requestExtensions;
+    }
+
+    public TBSRequest(
+        ASN1Sequence    seq)
+    {
+        int    index = 0;
+
+        if (seq.getObjectAt(0) instanceof ASN1TaggedObject)
+        {
+            ASN1TaggedObject    o = (ASN1TaggedObject)seq.getObjectAt(0);
+
+            if (o.getTagNo() == 0)
+            {
+                version = DERInteger.getInstance((ASN1TaggedObject)seq.getObjectAt(0), true);
+                index++;
+            }
+            else
+            {
+                version = V1;
+            }
+        }
+        else
+        {
+            version = V1;
+        }
+
+        if (seq.getObjectAt(index) instanceof ASN1TaggedObject)
+        {
+            requestorName = GeneralName.getInstance((ASN1TaggedObject)seq.getObjectAt(index++), true);
+        }
+        
+        requestList = (ASN1Sequence)seq.getObjectAt(index++);
+
+        if (seq.size() == (index + 1))
+        {
+            requestExtensions = X509Extensions.getInstance((ASN1TaggedObject)seq.getObjectAt(index), true);
+        }
+    }
+
+    public static TBSRequest getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static TBSRequest getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof TBSRequest)
+        {
+            return (TBSRequest)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new TBSRequest((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public DERInteger getVersion()
+    {
+        return version;
+    }
+
+    public GeneralName getRequestorName()
+    {
+        return requestorName;
+    }
+
+    public ASN1Sequence getRequestList()
+    {
+        return requestList;
+    }
+
+    public X509Extensions getRequestExtensions()
+    {
+        return requestExtensions;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * TBSRequest      ::=     SEQUENCE {
+     *     version             [0]     EXPLICIT Version DEFAULT v1,
+     *     requestorName       [1]     EXPLICIT GeneralName OPTIONAL,
+     *     requestList                 SEQUENCE OF Request,
+     *     requestExtensions   [2]     EXPLICIT Extensions OPTIONAL }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector    v = new ASN1EncodableVector();
+
+        //
+        // if default don't include.
+        //
+        if (!version.equals(V1))
+        {
+            v.add(new DERTaggedObject(true, 0, version));
+        }
+        
+        if (requestorName != null)
+        {
+            v.add(new DERTaggedObject(true, 1, requestorName));
+        }
+
+        v.add(requestList);
+
+        if (requestExtensions != null)
+        {
+            v.add(new DERTaggedObject(true, 2, requestExtensions));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java b/libcore/security/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java
new file mode 100644
index 0000000..4174e4d
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java
@@ -0,0 +1,26 @@
+package org.bouncycastle.asn1.oiw;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+public interface OIWObjectIdentifiers
+{
+    // id-SHA1 OBJECT IDENTIFIER ::=    
+    //   {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 }    //
+    static final DERObjectIdentifier    md4WithRSA              = new DERObjectIdentifier("1.3.14.3.2.2");
+    static final DERObjectIdentifier    md5WithRSA              = new DERObjectIdentifier("1.3.14.3.2.3");
+    static final DERObjectIdentifier    md4WithRSAEncryption    = new DERObjectIdentifier("1.3.14.3.2.4");
+    
+    static final DERObjectIdentifier    desCBC                  = new DERObjectIdentifier("1.3.14.3.2.7");
+    
+    static final DERObjectIdentifier    idSHA1                  = new DERObjectIdentifier("1.3.14.3.2.26");
+
+    static final DERObjectIdentifier    dsaWithSHA1             = new DERObjectIdentifier("1.3.14.3.2.27");
+
+    static final DERObjectIdentifier    sha1WithRSA             = new DERObjectIdentifier("1.3.14.3.2.29");
+    
+    // ElGamal Algorithm OBJECT IDENTIFIER ::=    
+    // {iso(1) identified-organization(3) oiw(14) dirservsig(7) algorithm(2) encryption(1) 1 }
+    //
+    static final DERObjectIdentifier    elGamalAlgorithm        = new DERObjectIdentifier("1.3.14.7.2.1.1");
+
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/Attribute.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/Attribute.java
new file mode 100644
index 0000000..56d6870
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/Attribute.java
@@ -0,0 +1,82 @@
+package org.bouncycastle.asn1.pkcs;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+
+public class Attribute
+    extends ASN1Encodable
+{
+    private DERObjectIdentifier attrType;
+    private ASN1Set             attrValues;
+
+    /**
+     * return an Attribute object from the given object.
+     *
+     * @param o the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static Attribute getInstance(
+        Object o)
+    {
+        if (o == null || o instanceof Attribute)
+        {
+            return (Attribute)o;
+        }
+        
+        if (o instanceof ASN1Sequence)
+        {
+            return new Attribute((ASN1Sequence)o);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+    
+    public Attribute(
+        ASN1Sequence seq)
+    {
+        attrType = (DERObjectIdentifier)seq.getObjectAt(0);
+        attrValues = (ASN1Set)seq.getObjectAt(1);
+    }
+
+    public Attribute(
+        DERObjectIdentifier attrType,
+        ASN1Set             attrValues)
+    {
+        this.attrType = attrType;
+        this.attrValues = attrValues;
+    }
+
+    public DERObjectIdentifier getAttrType()
+    {
+        return attrType;
+    }
+    
+    public ASN1Set getAttrValues()
+    {
+        return attrValues;
+    }
+
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * Attribute ::= SEQUENCE {
+     *     attrType OBJECT IDENTIFIER,
+     *     attrValues SET OF AttributeValue
+     * }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(attrType);
+        v.add(attrValues);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java
new file mode 100644
index 0000000..fe04a5c
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java
@@ -0,0 +1,47 @@
+package org.bouncycastle.asn1.pkcs;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.BERSequence;
+import org.bouncycastle.asn1.DERObject;
+
+public class AuthenticatedSafe
+    extends ASN1Encodable
+{
+    ContentInfo[]    info;
+
+    public AuthenticatedSafe(
+        ASN1Sequence  seq)
+    {
+        info = new ContentInfo[seq.size()];
+
+        for (int i = 0; i != info.length; i++)
+        {
+            info[i] = ContentInfo.getInstance(seq.getObjectAt(i));
+        }
+    }
+
+    public AuthenticatedSafe(
+        ContentInfo[]       info)
+    {
+        this.info = info;
+    }
+
+    public ContentInfo[] getContentInfo()
+    {
+        return info;
+    }
+
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        for (int i = 0; i != info.length; i++)
+        {
+            v.add(info[i]);
+        }
+
+        return new BERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/CertBag.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/CertBag.java
new file mode 100644
index 0000000..c781b4c
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/CertBag.java
@@ -0,0 +1,53 @@
+package org.bouncycastle.asn1.pkcs;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+public class CertBag
+    extends ASN1Encodable
+{
+    ASN1Sequence        seq;
+    DERObjectIdentifier certId;
+    DERObject           certValue;
+
+    public CertBag(
+        ASN1Sequence    seq)
+    {
+        this.seq = seq;
+        this.certId = (DERObjectIdentifier)seq.getObjectAt(0);
+        this.certValue = ((DERTaggedObject)seq.getObjectAt(1)).getObject();
+    }
+
+    public CertBag(
+        DERObjectIdentifier certId,
+        DERObject           certValue)
+    {
+        this.certId = certId;
+        this.certValue = certValue;
+    }
+
+    public DERObjectIdentifier getCertId()
+    {
+        return certId;
+    }
+
+    public DERObject getCertValue()
+    {
+        return certValue;
+    }
+
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(certId);
+        v.add(new DERTaggedObject(0, certValue));
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequest.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequest.java
new file mode 100644
index 0000000..ba28f54
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequest.java
@@ -0,0 +1,76 @@
+package org.bouncycastle.asn1.pkcs;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * PKCS10 Certification request object.
+ * <pre>
+ * CertificationRequest ::= SEQUENCE {
+ *   certificationRequestInfo  CertificationRequestInfo,
+ *   signatureAlgorithm        AlgorithmIdentifier{{ SignatureAlgorithms }},
+ *   signature                 BIT STRING
+ * }
+ * </pre>
+ */
+public class CertificationRequest
+    extends ASN1Encodable
+{
+    protected CertificationRequestInfo reqInfo = null;
+    protected AlgorithmIdentifier sigAlgId = null;
+    protected DERBitString sigBits = null;
+
+    protected CertificationRequest()
+    {
+    }
+
+    public CertificationRequest(
+        CertificationRequestInfo requestInfo,
+        AlgorithmIdentifier     algorithm,
+        DERBitString            signature)
+    {
+        this.reqInfo = requestInfo;
+        this.sigAlgId = algorithm;
+        this.sigBits = signature;
+    }
+
+    public CertificationRequest(
+        ASN1Sequence seq)
+    {
+        reqInfo = CertificationRequestInfo.getInstance(seq.getObjectAt(0));
+        sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
+        sigBits = (DERBitString)seq.getObjectAt(2);
+    }
+
+    public CertificationRequestInfo getCertificationRequestInfo()
+    {
+        return reqInfo;
+    }
+
+    public AlgorithmIdentifier getSignatureAlgorithm()
+    {
+        return sigAlgId;
+    }
+
+    public DERBitString getSignature()
+    {
+        return sigBits;
+    }
+
+    public DERObject toASN1Object()
+    {
+        // Construct the CertificateRequest
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(reqInfo);
+        v.add(sigAlgId);
+        v.add(sigBits);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java
new file mode 100644
index 0000000..3b9314d
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java
@@ -0,0 +1,129 @@
+package org.bouncycastle.asn1.pkcs;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x509.X509Name;
+
+/**
+ * PKCS10 CertificationRequestInfo object.
+ * <pre>
+ *  CertificationRequestInfo ::= SEQUENCE {
+ *   version             INTEGER { v1(0) } (v1,...),
+ *   subject             Name,
+ *   subjectPKInfo   SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
+ *   attributes          [0] Attributes{{ CRIAttributes }}
+ *  }
+ *
+ *  Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }}
+ *
+ *  Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE {
+ *    type    ATTRIBUTE.&id({IOSet}),
+ *    values  SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type})
+ *  }
+ * </pre>
+ */
+public class CertificationRequestInfo
+    extends ASN1Encodable
+{
+    DERInteger              version = new DERInteger(0);
+    X509Name                subject;
+    SubjectPublicKeyInfo    subjectPKInfo;
+    ASN1Set                 attributes = null;
+
+    public static CertificationRequestInfo getInstance(
+        Object  obj)
+    {
+        if (obj instanceof CertificationRequestInfo)
+        {
+            return (CertificationRequestInfo)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new CertificationRequestInfo((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public CertificationRequestInfo(
+        X509Name                subject,
+        SubjectPublicKeyInfo    pkInfo,
+        ASN1Set                 attributes)
+    {
+        this.subject = subject;
+        this.subjectPKInfo = pkInfo;
+        this.attributes = attributes;
+
+        if ((subject == null) || (version == null) || (subjectPKInfo == null))
+        {
+            throw new IllegalArgumentException("Not all mandatory fields set in CertificationRequestInfo generator.");
+        }
+    }
+
+    public CertificationRequestInfo(
+        ASN1Sequence  seq)
+    {
+        version = (DERInteger)seq.getObjectAt(0);
+
+        subject = X509Name.getInstance(seq.getObjectAt(1));
+        subjectPKInfo = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(2));
+
+        //
+        // some CertificationRequestInfo objects seem to treat this field
+        // as optional.
+        //
+        if (seq.size() > 3)
+        {
+            DERTaggedObject tagobj = (DERTaggedObject)seq.getObjectAt(3);
+            attributes = ASN1Set.getInstance(tagobj, false);
+        }
+
+        if ((subject == null) || (version == null) || (subjectPKInfo == null))
+        {
+            throw new IllegalArgumentException("Not all mandatory fields set in CertificationRequestInfo generator.");
+        }
+    }
+
+    public DERInteger getVersion()
+    {
+        return version;
+    }
+
+    public X509Name getSubject()
+    {
+        return subject;
+    }
+
+    public SubjectPublicKeyInfo getSubjectPublicKeyInfo()
+    {
+        return subjectPKInfo;
+    }
+
+    public ASN1Set getAttributes()
+    {
+        return attributes;
+    }
+
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(version);
+        v.add(subject);
+        v.add(subjectPKInfo);
+
+        if (attributes != null)
+        {
+            v.add(new DERTaggedObject(false, 0, attributes));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/ContentInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/ContentInfo.java
new file mode 100644
index 0000000..49b3a70
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/ContentInfo.java
@@ -0,0 +1,90 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.BERSequence;
+import org.bouncycastle.asn1.BERTaggedObject;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+public class ContentInfo
+    extends ASN1Encodable
+    implements PKCSObjectIdentifiers
+{
+    private DERObjectIdentifier contentType;
+    private DEREncodable        content;
+
+    public static ContentInfo getInstance(
+        Object  obj)
+    {
+        if (obj instanceof ContentInfo)
+        {
+            return (ContentInfo)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new ContentInfo((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public ContentInfo(
+        ASN1Sequence  seq)
+    {
+        Enumeration   e = seq.getObjects();
+
+        contentType = (DERObjectIdentifier)e.nextElement();
+
+        if (e.hasMoreElements())
+        {
+            content = ((DERTaggedObject)e.nextElement()).getObject();
+        }
+    }
+
+    public ContentInfo(
+        DERObjectIdentifier contentType,
+        DEREncodable        content)
+    {
+        this.contentType = contentType;
+        this.content = content;
+    }
+
+    public DERObjectIdentifier getContentType()
+    {
+        return contentType;
+    }
+
+    public DEREncodable getContent()
+    {
+        return content;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * ContentInfo ::= SEQUENCE {
+     *          contentType ContentType,
+     *          content
+     *          [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(contentType);
+
+        if (content != null)
+        {
+            v.add(new BERTaggedObject(0, content));
+        }
+
+        return new BERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/DHParameter.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/DHParameter.java
new file mode 100644
index 0000000..34537fa
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/DHParameter.java
@@ -0,0 +1,88 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+public class DHParameter
+    extends ASN1Encodable
+{
+    DERInteger      p, g, l;
+
+    public DHParameter(
+        BigInteger  p,
+        BigInteger  g,
+        int         l)
+    {
+        this.p = new DERInteger(p);
+        this.g = new DERInteger(g);
+
+        if (l != 0)
+        {
+            this.l = new DERInteger(l);
+        }
+        else
+        {
+            this.l = null;
+        }
+    }
+
+    public DHParameter(
+        ASN1Sequence  seq)
+    {
+        Enumeration     e = seq.getObjects();
+
+        p = (DERInteger)e.nextElement();
+        g = (DERInteger)e.nextElement();
+
+        if (e.hasMoreElements())
+        {
+            l = (DERInteger)e.nextElement();
+        }
+        else
+        {
+            l = null;
+        }
+    }
+
+    public BigInteger getP()
+    {
+        return p.getPositiveValue();
+    }
+
+    public BigInteger getG()
+    {
+        return g.getPositiveValue();
+    }
+
+    public BigInteger getL()
+    {
+        if (l == null)
+        {
+            return null;
+        }
+
+        return l.getPositiveValue();
+    }
+
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(p);
+        v.add(g);
+
+        if (this.getL() != null)
+        {
+            v.add(l);
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java
new file mode 100644
index 0000000..37d1303
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java
@@ -0,0 +1,104 @@
+package org.bouncycastle.asn1.pkcs;
+
+import org.bouncycastle.asn1.*;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * The EncryptedData object.
+ * <pre>
+ *      EncryptedData ::= SEQUENCE {
+ *           version Version,
+ *           encryptedContentInfo EncryptedContentInfo
+ *      }
+ *
+ *
+ *      EncryptedContentInfo ::= SEQUENCE {
+ *          contentType ContentType,
+ *          contentEncryptionAlgorithm  ContentEncryptionAlgorithmIdentifier,
+ *          encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+ *    }
+ *
+ *    EncryptedContent ::= OCTET STRING
+ * </pre>
+ */
+public class EncryptedData
+    extends ASN1Encodable
+{
+    ASN1Sequence                data;
+    DERObjectIdentifier         bagId;
+    DERObject                   bagValue;
+
+    public static EncryptedData getInstance(
+         Object  obj)
+    {
+         if (obj instanceof EncryptedData)
+         {
+             return (EncryptedData)obj;
+         }
+         else if (obj instanceof ASN1Sequence)
+         {
+             return new EncryptedData((ASN1Sequence)obj);
+         }
+
+         throw new IllegalArgumentException("unknown object in factory");
+    }
+     
+    public EncryptedData(
+        ASN1Sequence seq)
+    {
+        int version = ((DERInteger)seq.getObjectAt(0)).getValue().intValue();
+
+        if (version != 0)
+        {
+            throw new IllegalArgumentException("sequence not version 0");
+        }
+
+        this.data = (ASN1Sequence)seq.getObjectAt(1);
+    }
+
+    public EncryptedData(
+        DERObjectIdentifier     contentType,
+        AlgorithmIdentifier     encryptionAlgorithm,
+        DEREncodable            content)
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(contentType);
+        v.add(encryptionAlgorithm.getDERObject());
+        v.add(new BERTaggedObject(false, 0, content));
+
+        data = new BERSequence(v);
+    }
+        
+    public DERObjectIdentifier getContentType()
+    {
+        return (DERObjectIdentifier)data.getObjectAt(0);
+    }
+
+    public AlgorithmIdentifier getEncryptionAlgorithm()
+    {
+        return AlgorithmIdentifier.getInstance(data.getObjectAt(1));
+    }
+
+    public ASN1OctetString getContent()
+    {
+        if (data.size() == 3)
+        {
+            DERTaggedObject o = (DERTaggedObject)data.getObjectAt(2);
+
+            return ASN1OctetString.getInstance(o.getObject());
+        }
+
+        return null;
+    }
+
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(new DERInteger(0));
+        v.add(data);
+
+        return new BERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java
new file mode 100644
index 0000000..b46c13f
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java
@@ -0,0 +1,86 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class EncryptedPrivateKeyInfo
+    extends ASN1Encodable
+{
+    private AlgorithmIdentifier algId;
+    private ASN1OctetString     data;
+
+    public EncryptedPrivateKeyInfo(
+        ASN1Sequence  seq)
+    {
+        Enumeration e = seq.getObjects();
+
+        algId = AlgorithmIdentifier.getInstance(e.nextElement());
+        data = (ASN1OctetString)e.nextElement();
+    }
+
+    public EncryptedPrivateKeyInfo(
+        AlgorithmIdentifier algId,
+        byte[]              encoding)
+    {
+        this.algId = algId;
+        this.data = new DEROctetString(encoding);
+    }
+
+    public static EncryptedPrivateKeyInfo getInstance(
+        Object  obj)
+    {
+        if (obj instanceof EncryptedData)
+        {
+            return (EncryptedPrivateKeyInfo)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        { 
+            return new EncryptedPrivateKeyInfo((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+    
+    public AlgorithmIdentifier getEncryptionAlgorithm()
+    {
+        return algId;
+    }
+
+    public byte[] getEncryptedData()
+    {
+        return data.getOctets();
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * EncryptedPrivateKeyInfo ::= SEQUENCE {
+     *      encryptionAlgorithm AlgorithmIdentifier {{KeyEncryptionAlgorithms}},
+     *      encryptedData EncryptedData
+     * }
+     *
+     * EncryptedData ::= OCTET STRING
+     *
+     * KeyEncryptionAlgorithms ALGORITHM-IDENTIFIER ::= {
+     *          ... -- For local profiles
+     * }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(algId);
+        v.add(data);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java
new file mode 100644
index 0000000..eb9b326
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java
@@ -0,0 +1,38 @@
+package org.bouncycastle.asn1.pkcs;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class EncryptionScheme
+    extends AlgorithmIdentifier
+{   
+    DERObject   objectId;
+    DERObject   obj;
+
+    EncryptionScheme(
+        ASN1Sequence  seq)
+    {   
+        super(seq);
+        
+        objectId = (DERObject)seq.getObjectAt(0);
+        obj = (DERObject)seq.getObjectAt(1);
+    }
+
+    public DERObject getObject()
+    {
+        return obj;
+    }
+
+    public DERObject getDERObject()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(objectId);
+        v.add(obj);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/IssuerAndSerialNumber.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/IssuerAndSerialNumber.java
new file mode 100644
index 0000000..088d213
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/IssuerAndSerialNumber.java
@@ -0,0 +1,76 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.X509Name;
+
+public class IssuerAndSerialNumber
+    extends ASN1Encodable
+{
+    X509Name    name;
+    DERInteger  certSerialNumber;
+
+    public static IssuerAndSerialNumber getInstance(
+        Object  obj)
+    {
+        if (obj instanceof IssuerAndSerialNumber)
+        {
+            return (IssuerAndSerialNumber)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new IssuerAndSerialNumber((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public IssuerAndSerialNumber(
+        ASN1Sequence    seq)
+    {
+        this.name = X509Name.getInstance(seq.getObjectAt(0));
+        this.certSerialNumber = (DERInteger)seq.getObjectAt(1);
+    }
+
+    public IssuerAndSerialNumber(
+        X509Name    name,
+        BigInteger  certSerialNumber)
+    {
+        this.name = name;
+        this.certSerialNumber = new DERInteger(certSerialNumber);
+    }
+
+    public IssuerAndSerialNumber(
+        X509Name    name,
+        DERInteger  certSerialNumber)
+    {
+        this.name = name;
+        this.certSerialNumber = certSerialNumber;
+    }
+
+    public X509Name getName()
+    {
+        return name;
+    }
+
+    public DERInteger getCertificateSerialNumber()
+    {
+        return certSerialNumber;
+    }
+
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector    v = new ASN1EncodableVector();
+
+        v.add(name);
+        v.add(certSerialNumber);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java
new file mode 100644
index 0000000..50c9ef2
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java
@@ -0,0 +1,23 @@
+package org.bouncycastle.asn1.pkcs;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class KeyDerivationFunc
+    extends AlgorithmIdentifier
+{
+    KeyDerivationFunc(
+        ASN1Sequence  seq)
+    {
+        super(seq);
+    }
+    
+    KeyDerivationFunc(
+        DERObjectIdentifier id,
+        ASN1Encodable       params)
+    {
+        super(id, params);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/MacData.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/MacData.java
new file mode 100644
index 0000000..8f58c82
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/MacData.java
@@ -0,0 +1,89 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.DigestInfo;
+
+public class MacData
+    extends ASN1Encodable
+{
+    DigestInfo                  digInfo;
+    byte[]                      salt;
+    BigInteger                  iterationCount;
+
+    public static MacData getInstance(
+        Object  obj)
+    {
+        if (obj instanceof MacData)
+        {
+            return (MacData)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new MacData((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public MacData(
+        ASN1Sequence seq)
+    {
+        this.digInfo = DigestInfo.getInstance(seq.getObjectAt(0));
+
+        this.salt = ((ASN1OctetString)seq.getObjectAt(1)).getOctets();
+
+        if (seq.size() == 3)
+        {
+            this.iterationCount = ((DERInteger)seq.getObjectAt(2)).getValue();
+        }
+        else
+        {
+            this.iterationCount = BigInteger.valueOf(1);
+        }
+    }
+
+    public MacData(
+        DigestInfo  digInfo,
+        byte[]      salt,
+        int         iterationCount)
+    {
+        this.digInfo = digInfo;
+        this.salt = salt;
+        this.iterationCount = BigInteger.valueOf(iterationCount);
+    }
+
+    public DigestInfo getMac()
+    {
+        return digInfo;
+    }
+
+    public byte[] getSalt()
+    {
+        return salt;
+    }
+
+    public BigInteger getIterationCount()
+    {
+        return iterationCount;
+    }
+
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(digInfo);
+        v.add(new DEROctetString(salt));
+        v.add(new DERInteger(iterationCount));
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Algorithms.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Algorithms.java
new file mode 100644
index 0000000..2817903
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Algorithms.java
@@ -0,0 +1,77 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * @deprecated - use AlgorithmIdentifier and PBES2Parameters
+ */
+public class PBES2Algorithms
+    extends AlgorithmIdentifier implements PKCSObjectIdentifiers
+{
+    private DERObjectIdentifier objectId;
+    private KeyDerivationFunc   func;
+    private EncryptionScheme    scheme;
+
+    public PBES2Algorithms(
+        ASN1Sequence  obj)
+    {
+        super(obj);
+
+        Enumeration     e = obj.getObjects();
+
+        objectId = (DERObjectIdentifier)e.nextElement();
+
+        ASN1Sequence seq = (ASN1Sequence)e.nextElement();
+
+        e = seq.getObjects();
+
+        ASN1Sequence  funcSeq = (ASN1Sequence)e.nextElement();
+
+        if (funcSeq.getObjectAt(0).equals(id_PBKDF2))
+        {
+            func = new KeyDerivationFunc(id_PBKDF2, PBKDF2Params.getInstance(funcSeq.getObjectAt(1)));
+        }
+        else
+        {
+            func = new KeyDerivationFunc(funcSeq);
+        }
+
+        scheme = new EncryptionScheme((ASN1Sequence)e.nextElement());
+    }
+
+    public DERObjectIdentifier getObjectId()
+    {
+        return objectId;
+    }
+
+    public KeyDerivationFunc getKeyDerivationFunc()
+    {
+        return func;
+    }
+
+    public EncryptionScheme getEncryptionScheme()
+    {
+        return scheme;
+    }
+
+    public DERObject getDERObject()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+        ASN1EncodableVector  subV = new ASN1EncodableVector();
+
+        v.add(objectId);
+
+        subV.add(func);
+        subV.add(scheme);
+        v.add(new DERSequence(subV));
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Parameters.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Parameters.java
new file mode 100644
index 0000000..57c773c
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Parameters.java
@@ -0,0 +1,55 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+public class PBES2Parameters
+    extends ASN1Encodable
+    implements PKCSObjectIdentifiers
+{
+    private KeyDerivationFunc   func;
+    private EncryptionScheme    scheme;
+
+    public PBES2Parameters(
+        ASN1Sequence  obj)
+    {
+        Enumeration e = obj.getObjects();
+        ASN1Sequence  funcSeq = (ASN1Sequence)e.nextElement();
+
+        if (funcSeq.getObjectAt(0).equals(id_PBKDF2))
+        {
+            func = new KeyDerivationFunc(id_PBKDF2, PBKDF2Params.getInstance(funcSeq.getObjectAt(1)));
+        }
+        else
+        {
+            func = new KeyDerivationFunc(funcSeq);
+        }
+
+        scheme = new EncryptionScheme((ASN1Sequence)e.nextElement());
+    }
+
+    public KeyDerivationFunc getKeyDerivationFunc()
+    {
+        return func;
+    }
+
+    public EncryptionScheme getEncryptionScheme()
+    {
+        return scheme;
+    }
+
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(func);
+        v.add(scheme);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java
new file mode 100644
index 0000000..311766e
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java
@@ -0,0 +1,98 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+
+public class PBKDF2Params
+    extends ASN1Encodable
+{
+    ASN1OctetString     octStr;
+    DERInteger          iterationCount;
+    DERInteger          keyLength;
+
+    public static PBKDF2Params getInstance(
+        Object  obj)
+    {
+        if (obj instanceof PBKDF2Params)
+        {
+            return (PBKDF2Params)obj;
+        }
+
+        if (obj instanceof ASN1Sequence)
+        {
+            return new PBKDF2Params((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+    
+    public PBKDF2Params(
+        byte[]  salt,
+        int     iterationCount)
+    {
+        this.octStr = new DEROctetString(salt);
+        this.iterationCount = new DERInteger(iterationCount);
+    }
+    
+    public PBKDF2Params(
+        ASN1Sequence  seq)
+    {
+        Enumeration e = seq.getObjects();
+
+        octStr = (ASN1OctetString)e.nextElement();
+        iterationCount = (DERInteger)e.nextElement();
+
+        if (e.hasMoreElements())
+        {
+            keyLength = (DERInteger)e.nextElement();
+        }
+        else
+        {
+            keyLength = null;
+        }
+    }
+
+    public byte[] getSalt()
+    {
+        return octStr.getOctets();
+    }
+
+    public BigInteger getIterationCount()
+    {
+        return iterationCount.getValue();
+    }
+
+    public BigInteger getKeyLength()
+    {
+        if (keyLength != null)
+        {
+            return keyLength.getValue();
+        }
+
+        return null;
+    }
+
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(octStr);
+        v.add(iterationCount);
+
+        if (keyLength != null)
+        {
+            v.add(keyLength);
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java
new file mode 100644
index 0000000..5dc3a5d
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java
@@ -0,0 +1,69 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+
+public class PKCS12PBEParams
+    extends ASN1Encodable
+{
+    DERInteger      iterations;
+    ASN1OctetString iv;
+
+    public PKCS12PBEParams(
+        byte[]      salt,
+        int         iterations)
+    {
+        this.iv = new DEROctetString(salt);
+        this.iterations = new DERInteger(iterations);
+    }
+
+    public PKCS12PBEParams(
+        ASN1Sequence  seq)
+    {
+        iv = (ASN1OctetString)seq.getObjectAt(0);
+        iterations = (DERInteger)seq.getObjectAt(1);
+    }
+
+    public static PKCS12PBEParams getInstance(
+        Object  obj)
+    {
+        if (obj instanceof PKCS12PBEParams)
+        {
+            return (PKCS12PBEParams)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new PKCS12PBEParams((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public BigInteger getIterations()
+    {
+        return iterations.getValue();
+    }
+
+    public byte[] getIV()
+    {
+        return iv.getOctets();
+    }
+
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(iv);
+        v.add(iterations);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
new file mode 100644
index 0000000..48fdb93
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
@@ -0,0 +1,204 @@
+package org.bouncycastle.asn1.pkcs;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+public interface PKCSObjectIdentifiers
+{
+    //
+    // pkcs-1 OBJECT IDENTIFIER ::= {
+    //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
+    //
+    static final String                 pkcs_1                    = "1.2.840.113549.1.1";
+    static final DERObjectIdentifier    rsaEncryption             = new DERObjectIdentifier(pkcs_1 + ".1");
+    static final DERObjectIdentifier    md2WithRSAEncryption      = new DERObjectIdentifier(pkcs_1 + ".2");
+    static final DERObjectIdentifier    md4WithRSAEncryption      = new DERObjectIdentifier(pkcs_1 + ".3");
+    static final DERObjectIdentifier    md5WithRSAEncryption      = new DERObjectIdentifier(pkcs_1 + ".4");
+    static final DERObjectIdentifier    sha1WithRSAEncryption     = new DERObjectIdentifier(pkcs_1 + ".5");
+    static final DERObjectIdentifier    srsaOAEPEncryptionSET     = new DERObjectIdentifier(pkcs_1 + ".6");
+    static final DERObjectIdentifier    id_RSAES_OAEP             = new DERObjectIdentifier(pkcs_1 + ".7");
+    static final DERObjectIdentifier    id_mgf1                   = new DERObjectIdentifier(pkcs_1 + ".8");
+    static final DERObjectIdentifier    id_pSpecified             = new DERObjectIdentifier(pkcs_1 + ".9");
+    static final DERObjectIdentifier    id_RSASSA_PSS             = new DERObjectIdentifier(pkcs_1 + ".10");
+    static final DERObjectIdentifier    sha256WithRSAEncryption   = new DERObjectIdentifier(pkcs_1 + ".11");
+    static final DERObjectIdentifier    sha384WithRSAEncryption   = new DERObjectIdentifier(pkcs_1 + ".12");
+    static final DERObjectIdentifier    sha512WithRSAEncryption   = new DERObjectIdentifier(pkcs_1 + ".13");
+    static final DERObjectIdentifier    sha224WithRSAEncryption   = new DERObjectIdentifier(pkcs_1 + ".14");
+
+    //
+    // pkcs-3 OBJECT IDENTIFIER ::= {
+    //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 3 }
+    //
+    static final String                 pkcs_3                  = "1.2.840.113549.1.3";
+    static final DERObjectIdentifier    dhKeyAgreement          = new DERObjectIdentifier(pkcs_3 + ".1");
+
+    //
+    // pkcs-5 OBJECT IDENTIFIER ::= {
+    //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 5 }
+    //
+    static final String                 pkcs_5                  = "1.2.840.113549.1.5";
+
+    static final DERObjectIdentifier    pbeWithMD2AndDES_CBC    = new DERObjectIdentifier(pkcs_5 + ".1");
+    static final DERObjectIdentifier    pbeWithMD2AndRC2_CBC    = new DERObjectIdentifier(pkcs_5 + ".4");
+    static final DERObjectIdentifier    pbeWithMD5AndDES_CBC    = new DERObjectIdentifier(pkcs_5 + ".3");
+    static final DERObjectIdentifier    pbeWithMD5AndRC2_CBC    = new DERObjectIdentifier(pkcs_5 + ".6");
+    static final DERObjectIdentifier    pbeWithSHA1AndDES_CBC   = new DERObjectIdentifier(pkcs_5 + ".10");
+    static final DERObjectIdentifier    pbeWithSHA1AndRC2_CBC   = new DERObjectIdentifier(pkcs_5 + ".11");
+
+    static final DERObjectIdentifier    id_PBES2                = new DERObjectIdentifier(pkcs_5 + ".13");
+
+    static final DERObjectIdentifier    id_PBKDF2               = new DERObjectIdentifier(pkcs_5 + ".12");
+
+    //
+    // encryptionAlgorithm OBJECT IDENTIFIER ::= {
+    //       iso(1) member-body(2) us(840) rsadsi(113549) 3 }
+    //
+    static final String                 encryptionAlgorithm     = "1.2.840.113549.3";
+
+    static final DERObjectIdentifier    des_EDE3_CBC            = new DERObjectIdentifier(encryptionAlgorithm + ".7");
+    static final DERObjectIdentifier    RC2_CBC                 = new DERObjectIdentifier(encryptionAlgorithm + ".2");
+
+    //
+    // object identifiers for digests
+    //
+    static final String                 digestAlgorithm     = "1.2.840.113549.2";
+    //
+    // md2 OBJECT IDENTIFIER ::=
+    //      {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 2}
+    //
+    static final DERObjectIdentifier    md2                     = new DERObjectIdentifier(digestAlgorithm + ".2");
+
+    //
+    // md4 OBJECT IDENTIFIER ::=
+    //      {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 4}
+    //
+    static final DERObjectIdentifier    md4 = new DERObjectIdentifier(digestAlgorithm + ".4");
+
+    //
+    // md5 OBJECT IDENTIFIER ::=
+    //      {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 5}
+    //
+    static final DERObjectIdentifier    md5                     = new DERObjectIdentifier(digestAlgorithm + ".5");
+
+    static final DERObjectIdentifier    id_hmacWithSHA1         = new DERObjectIdentifier(digestAlgorithm + ".7");
+    static final DERObjectIdentifier    id_hmacWithSHA224       = new DERObjectIdentifier(digestAlgorithm + ".8");
+    static final DERObjectIdentifier    id_hmacWithSHA256       = new DERObjectIdentifier(digestAlgorithm + ".9");
+    static final DERObjectIdentifier    id_hmacWithSHA384       = new DERObjectIdentifier(digestAlgorithm + ".10");
+    static final DERObjectIdentifier    id_hmacWithSHA512       = new DERObjectIdentifier(digestAlgorithm + ".11");
+
+    //
+    // pkcs-7 OBJECT IDENTIFIER ::= {
+    //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 7 }
+    //
+    static final String                 pkcs_7                  = "1.2.840.113549.1.7";
+    static final DERObjectIdentifier    data                    = new DERObjectIdentifier(pkcs_7 + ".1");
+    static final DERObjectIdentifier    signedData              = new DERObjectIdentifier(pkcs_7 + ".2");
+    static final DERObjectIdentifier    envelopedData           = new DERObjectIdentifier(pkcs_7 + ".3");
+    static final DERObjectIdentifier    signedAndEnvelopedData  = new DERObjectIdentifier(pkcs_7 + ".4");
+    static final DERObjectIdentifier    digestedData            = new DERObjectIdentifier(pkcs_7 + ".5");
+    static final DERObjectIdentifier    encryptedData           = new DERObjectIdentifier(pkcs_7 + ".6");
+
+    //
+    // pkcs-9 OBJECT IDENTIFIER ::= {
+    //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 }
+    //
+    static final String                 pkcs_9                  = "1.2.840.113549.1.9";
+
+    static final DERObjectIdentifier    pkcs_9_at_emailAddress  = new DERObjectIdentifier(pkcs_9 + ".1");
+    static final DERObjectIdentifier    pkcs_9_at_unstructuredName = new DERObjectIdentifier(pkcs_9 + ".2");
+    static final DERObjectIdentifier    pkcs_9_at_contentType = new DERObjectIdentifier(pkcs_9 + ".3");
+    static final DERObjectIdentifier    pkcs_9_at_messageDigest = new DERObjectIdentifier(pkcs_9 + ".4");
+    static final DERObjectIdentifier    pkcs_9_at_signingTime = new DERObjectIdentifier(pkcs_9 + ".5");
+    static final DERObjectIdentifier    pkcs_9_at_counterSignature = new DERObjectIdentifier(pkcs_9 + ".6");
+    static final DERObjectIdentifier    pkcs_9_at_challengePassword = new DERObjectIdentifier(pkcs_9 + ".7");
+    static final DERObjectIdentifier    pkcs_9_at_unstructuredAddress = new DERObjectIdentifier(pkcs_9 + ".8");
+    static final DERObjectIdentifier    pkcs_9_at_extendedCertificateAttributes = new DERObjectIdentifier(pkcs_9 + ".9");
+
+    static final DERObjectIdentifier    pkcs_9_at_signingDescription = new DERObjectIdentifier(pkcs_9 + ".13");
+    static final DERObjectIdentifier    pkcs_9_at_extensionRequest = new DERObjectIdentifier(pkcs_9 + ".14");
+    static final DERObjectIdentifier    pkcs_9_at_smimeCapabilities = new DERObjectIdentifier(pkcs_9 + ".15");
+
+    static final DERObjectIdentifier    pkcs_9_at_friendlyName  = new DERObjectIdentifier(pkcs_9 + ".20");
+    static final DERObjectIdentifier    pkcs_9_at_localKeyId    = new DERObjectIdentifier(pkcs_9 + ".21");
+
+    static final DERObjectIdentifier    x509certType            = new DERObjectIdentifier(pkcs_9 + ".22.1");
+
+    static final DERObjectIdentifier    id_alg_PWRI_KEK    = new DERObjectIdentifier(pkcs_9 + ".16.3.9");
+
+    //
+    // SMIME capability sub oids.
+    //
+    static final DERObjectIdentifier    preferSignedData        = new DERObjectIdentifier(pkcs_9 + ".15.1");
+    static final DERObjectIdentifier    canNotDecryptAny        = new DERObjectIdentifier(pkcs_9 + ".15.2");
+    static final DERObjectIdentifier    sMIMECapabilitiesVersions = new DERObjectIdentifier(pkcs_9 + ".15.3");
+
+    //
+    // other SMIME attributes
+    //
+    static final DERObjectIdentifier    id_aa_receiptRequest    = new DERObjectIdentifier(pkcs_9 + ".16.2.1");
+
+    //
+    // id-ct OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+    // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) ct(1)}
+    //
+    static String id_ct = "1.2.840.113549.1.9.16.1";
+    
+    static final DERObjectIdentifier    id_ct_TSTInfo           = new DERObjectIdentifier(id_ct + ".4");
+    static final DERObjectIdentifier    id_ct_compressedData    = new DERObjectIdentifier(id_ct + ".9");
+    
+    //
+    // id-cti OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+    // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) cti(6)}
+    //
+    static String id_cti = "1.2.840.113549.1.9.16.6";
+    
+    static final DERObjectIdentifier    id_cti_ets_proofOfOrigin  = new DERObjectIdentifier(id_cti + ".1");
+    static final DERObjectIdentifier    id_cti_ets_proofOfReceipt = new DERObjectIdentifier(id_cti + ".2");
+    static final DERObjectIdentifier    id_cti_ets_proofOfDelivery = new DERObjectIdentifier(id_cti + ".3");
+    static final DERObjectIdentifier    id_cti_ets_proofOfSender = new DERObjectIdentifier(id_cti + ".4");
+    static final DERObjectIdentifier    id_cti_ets_proofOfApproval = new DERObjectIdentifier(id_cti + ".5");
+    static final DERObjectIdentifier    id_cti_ets_proofOfCreation = new DERObjectIdentifier(id_cti + ".6");
+    
+    //
+    // id-aa OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+    // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) attributes(2)}
+    //
+    static String id_aa = "1.2.840.113549.1.9.16.2";
+    
+    /*
+     * id-aa-encrypKeyPref OBJECT IDENTIFIER ::= {id-aa 11}
+     * 
+     */
+    static DERObjectIdentifier id_aa_encrypKeyPref = new DERObjectIdentifier(id_aa + ".11");
+    static DERObjectIdentifier id_aa_signingCertificate = new DERObjectIdentifier(id_aa + ".12");
+
+    static final DERObjectIdentifier id_aa_contentIdentifier = new DERObjectIdentifier(id_aa + ".7"); // See RFC 2634
+    static final DERObjectIdentifier id_aa_signatureTimeStampToken = new DERObjectIdentifier(id_aa + ".14"); // See RFC 3126
+    static final DERObjectIdentifier id_aa_sigPolicyId = new DERObjectIdentifier(id_aa + ".15"); // See RFC 3126
+    static final DERObjectIdentifier id_aa_commitmentType = new DERObjectIdentifier(id_aa + ".16"); // See RFC 3126
+    static final DERObjectIdentifier id_aa_signerLocation = new DERObjectIdentifier(id_aa + ".17"); // See RFC 3126
+    static final DERObjectIdentifier id_aa_otherSigCert = new DERObjectIdentifier(id_aa + ".19"); // See RFC 3126
+    //
+    // pkcs-12 OBJECT IDENTIFIER ::= {
+    //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 12 }
+    //
+    static final String                 pkcs_12                  = "1.2.840.113549.1.12";
+    static final String                 bagtypes                 = pkcs_12 + ".10.1";
+
+    static final DERObjectIdentifier    keyBag                  = new DERObjectIdentifier(bagtypes + ".1");
+    static final DERObjectIdentifier    pkcs8ShroudedKeyBag     = new DERObjectIdentifier(bagtypes + ".2");
+    static final DERObjectIdentifier    certBag                 = new DERObjectIdentifier(bagtypes + ".3");
+    static final DERObjectIdentifier    crlBag                  = new DERObjectIdentifier(bagtypes + ".4");
+    static final DERObjectIdentifier    secretBag               = new DERObjectIdentifier(bagtypes + ".5");
+    static final DERObjectIdentifier    safeContentsBag         = new DERObjectIdentifier(bagtypes + ".6");
+
+    static final String pkcs_12PbeIds  = pkcs_12 + ".1";
+
+    static final DERObjectIdentifier    pbeWithSHAAnd128BitRC4 = new DERObjectIdentifier(pkcs_12PbeIds + ".1");
+    static final DERObjectIdentifier    pbeWithSHAAnd40BitRC4  = new DERObjectIdentifier(pkcs_12PbeIds + ".2");
+    static final DERObjectIdentifier    pbeWithSHAAnd3_KeyTripleDES_CBC = new DERObjectIdentifier(pkcs_12PbeIds + ".3");
+    static final DERObjectIdentifier    pbeWithSHAAnd2_KeyTripleDES_CBC = new DERObjectIdentifier(pkcs_12PbeIds + ".4");
+    static final DERObjectIdentifier    pbeWithSHAAnd128BitRC2_CBC = new DERObjectIdentifier(pkcs_12PbeIds + ".5");
+    static final DERObjectIdentifier    pbewithSHAAnd40BitRC2_CBC = new DERObjectIdentifier(pkcs_12PbeIds + ".6");
+
+}
+
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/Pfx.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/Pfx.java
new file mode 100644
index 0000000..ba5292c
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/Pfx.java
@@ -0,0 +1,71 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.BERSequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+
+/**
+ * the infamous Pfx from PKCS12
+ */
+public class Pfx
+    extends ASN1Encodable
+    implements PKCSObjectIdentifiers
+{
+    private ContentInfo             contentInfo;
+    private MacData                 macData = null;
+
+    public Pfx(
+        ASN1Sequence   seq)
+    {
+        BigInteger  version = ((DERInteger)seq.getObjectAt(0)).getValue();
+        if (version.intValue() != 3)
+        {
+            throw new IllegalArgumentException("wrong version for PFX PDU");
+        }
+
+        contentInfo = ContentInfo.getInstance(seq.getObjectAt(1));
+
+        if (seq.size() == 3)
+        {
+            macData = MacData.getInstance(seq.getObjectAt(2));
+        }
+    }
+
+    public Pfx(
+        ContentInfo     contentInfo,
+        MacData         macData)
+    {
+        this.contentInfo = contentInfo;
+        this.macData = macData;
+    }
+
+    public ContentInfo getAuthSafe()
+    {
+        return contentInfo;
+    }
+
+    public MacData getMacData()
+    {
+        return macData;
+    }
+
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(new DERInteger(3));
+        v.add(contentInfo);
+
+        if (macData != null)
+        {
+            v.add(macData);
+        }
+
+        return new BERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java
new file mode 100644
index 0000000..5c384d8
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java
@@ -0,0 +1,135 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class PrivateKeyInfo
+    extends ASN1Encodable
+{
+    private DERObject               privKey;
+    private AlgorithmIdentifier     algId;
+    private ASN1Set                 attributes;
+
+    public static PrivateKeyInfo getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static PrivateKeyInfo getInstance(
+        Object  obj)
+    {
+        if (obj instanceof PrivateKeyInfo)
+        {
+            return (PrivateKeyInfo)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new PrivateKeyInfo((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+        
+    public PrivateKeyInfo(
+        AlgorithmIdentifier algId,
+        DERObject           privateKey)
+    {
+        this.privKey = privateKey;
+        this.algId = algId;
+    }
+
+    public PrivateKeyInfo(
+        ASN1Sequence  seq)
+    {
+        Enumeration e = seq.getObjects();
+
+        BigInteger  version = ((DERInteger)e.nextElement()).getValue();
+        if (version.intValue() != 0)
+        {
+            throw new IllegalArgumentException("wrong version for private key info");
+        }
+
+        algId = new AlgorithmIdentifier((ASN1Sequence)e.nextElement());
+
+        try
+        {
+            ASN1InputStream         aIn = new ASN1InputStream(((ASN1OctetString)e.nextElement()).getOctets());
+
+            privKey = aIn.readObject();
+        }
+        catch (IOException ex)
+        {
+            throw new IllegalArgumentException("Error recoverying private key from sequence");
+        }
+        
+        if (e.hasMoreElements())
+        {
+           attributes = ASN1Set.getInstance((ASN1TaggedObject)e.nextElement(), false);
+        }
+    }
+
+    public AlgorithmIdentifier getAlgorithmId()
+    {
+        return algId;
+    }
+
+    public DERObject getPrivateKey()
+    {
+        return privKey;
+    }
+    
+    public ASN1Set getAttributes()
+    {
+        return attributes;
+    }
+
+    /**
+     * write out an RSA private key with it's asscociated information
+     * as described in PKCS8.
+     * <pre>
+     *      PrivateKeyInfo ::= SEQUENCE {
+     *                              version Version,
+     *                              privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}},
+     *                              privateKey PrivateKey,
+     *                              attributes [0] IMPLICIT Attributes OPTIONAL 
+     *                          }
+     *      Version ::= INTEGER {v1(0)} (v1,...)
+     *
+     *      PrivateKey ::= OCTET STRING
+     *
+     *      Attributes ::= SET OF Attribute
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(new DERInteger(0));
+        v.add(algId);
+        v.add(new DEROctetString(privKey));
+
+        if (attributes != null)
+        {
+            v.add(new DERTaggedObject(false, 0, attributes));
+        }
+        
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/RC2CBCParameter.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/RC2CBCParameter.java
new file mode 100644
index 0000000..23508a4
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/RC2CBCParameter.java
@@ -0,0 +1,89 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+
+public class RC2CBCParameter
+    extends ASN1Encodable
+{
+    DERInteger      version;
+    ASN1OctetString iv;
+
+    public static RC2CBCParameter getInstance(
+        Object  o)
+    {
+        if (o instanceof ASN1Sequence)
+        {
+            return new RC2CBCParameter((ASN1Sequence)o);
+        }
+
+        throw new IllegalArgumentException("unknown object in RC2CBCParameter factory");
+    }
+
+    public RC2CBCParameter(
+        byte[]  iv)
+    {
+        this.version = null;
+        this.iv = new DEROctetString(iv);
+    }
+
+    public RC2CBCParameter(
+        int     parameterVersion,
+        byte[]  iv)
+    {
+        this.version = new DERInteger(parameterVersion);
+        this.iv = new DEROctetString(iv);
+    }
+
+    public RC2CBCParameter(
+        ASN1Sequence  seq)
+    {
+        if (seq.size() == 1)
+        {
+            version = null;
+            iv = (ASN1OctetString)seq.getObjectAt(0);
+        }
+        else
+        {
+            version = (DERInteger)seq.getObjectAt(0);
+            iv = (ASN1OctetString)seq.getObjectAt(1);
+        }
+    }
+
+    public BigInteger getRC2ParameterVersion()
+    {
+        if (version == null)
+        {
+            return null;
+        }
+
+        return version.getValue();
+    }
+
+    public byte[] getIV()
+    {
+        return iv.getOctets();
+    }
+
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        if (version != null)
+        {
+            v.add(version);
+        }
+
+        v.add(iv);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java
new file mode 100644
index 0000000..87537ff
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java
@@ -0,0 +1,153 @@
+package org.bouncycastle.asn1.pkcs;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class RSAESOAEPparams
+    extends ASN1Encodable
+{
+    private AlgorithmIdentifier hashAlgorithm;
+    private AlgorithmIdentifier maskGenAlgorithm;
+    private AlgorithmIdentifier pSourceAlgorithm;
+    
+    // BEGIN android-changed
+    public final static AlgorithmIdentifier DEFAULT_HASH_ALGORITHM = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.THE_ONE);
+    // END android-changed
+    public final static AlgorithmIdentifier DEFAULT_MASK_GEN_FUNCTION = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, DEFAULT_HASH_ALGORITHM);
+    public final static AlgorithmIdentifier DEFAULT_P_SOURCE_ALGORITHM = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(new byte[0]));
+    
+    public static RSAESOAEPparams getInstance(
+        Object  obj)
+    {
+        if (obj instanceof RSAESOAEPparams)
+        {
+            return (RSAESOAEPparams)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new RSAESOAEPparams((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+    
+    /**
+     * The default version
+     */
+    public RSAESOAEPparams()
+    {
+        hashAlgorithm = DEFAULT_HASH_ALGORITHM;
+        maskGenAlgorithm = DEFAULT_MASK_GEN_FUNCTION;
+        pSourceAlgorithm = DEFAULT_P_SOURCE_ALGORITHM;
+    }
+    
+    public RSAESOAEPparams(
+        AlgorithmIdentifier hashAlgorithm,
+        AlgorithmIdentifier maskGenAlgorithm,
+        AlgorithmIdentifier pSourceAlgorithm)
+    {
+        this.hashAlgorithm = hashAlgorithm;
+        this.maskGenAlgorithm = maskGenAlgorithm;
+        this.pSourceAlgorithm = pSourceAlgorithm;
+    }
+    
+    public RSAESOAEPparams(
+        ASN1Sequence seq)
+    {
+        hashAlgorithm = DEFAULT_HASH_ALGORITHM;
+        maskGenAlgorithm = DEFAULT_MASK_GEN_FUNCTION;
+        pSourceAlgorithm = DEFAULT_P_SOURCE_ALGORITHM;
+        
+        for (int i = 0; i != seq.size(); i++)
+        {
+            ASN1TaggedObject    o = (ASN1TaggedObject)seq.getObjectAt(i);
+            
+            switch (o.getTagNo())
+            {
+            case 0:
+                hashAlgorithm = AlgorithmIdentifier.getInstance(o, true);
+                break;
+            case 1:
+                maskGenAlgorithm = AlgorithmIdentifier.getInstance(o, true);
+                break;
+            case 2:
+                pSourceAlgorithm = AlgorithmIdentifier.getInstance(o, true);
+                break;
+            default:
+                throw new IllegalArgumentException("unknown tag");
+            }
+        }
+    }
+    
+    public AlgorithmIdentifier getHashAlgorithm()
+    {
+        return hashAlgorithm;
+    }
+    
+    public AlgorithmIdentifier getMaskGenAlgorithm()
+    {
+        return maskGenAlgorithm;
+    }
+    
+    public AlgorithmIdentifier getPSourceAlgorithm()
+    {
+        return pSourceAlgorithm;
+    }
+    
+    /**
+     * <pre>
+     *  RSAES-OAEP-params ::= SEQUENCE {
+     *     hashAlgorithm      [0] OAEP-PSSDigestAlgorithms     DEFAULT sha1,
+     *     maskGenAlgorithm   [1] PKCS1MGFAlgorithms  DEFAULT mgf1SHA1,
+     *     pSourceAlgorithm   [2] PKCS1PSourceAlgorithms  DEFAULT pSpecifiedEmpty
+     *   }
+     *  
+     *   OAEP-PSSDigestAlgorithms    ALGORITHM-IDENTIFIER ::= {
+     *     { OID id-sha1 PARAMETERS NULL   }|
+     *     { OID id-sha256 PARAMETERS NULL }|
+     *     { OID id-sha384 PARAMETERS NULL }|
+     *     { OID id-sha512 PARAMETERS NULL },
+     *     ...  -- Allows for future expansion --
+     *   }
+     *   PKCS1MGFAlgorithms    ALGORITHM-IDENTIFIER ::= {
+     *     { OID id-mgf1 PARAMETERS OAEP-PSSDigestAlgorithms },
+     *    ...  -- Allows for future expansion --
+     *   }
+     *   PKCS1PSourceAlgorithms    ALGORITHM-IDENTIFIER ::= {
+     *     { OID id-pSpecified PARAMETERS OCTET STRING },
+     *     ...  -- Allows for future expansion --
+     *  }
+     * </pre>
+     * @return the asn1 primitive representing the parameters.
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+        
+        if (!hashAlgorithm.equals(DEFAULT_HASH_ALGORITHM))
+        {
+            v.add(new DERTaggedObject(true, 0, hashAlgorithm));
+        }
+        
+        if (!maskGenAlgorithm.equals(DEFAULT_MASK_GEN_FUNCTION))
+        {
+            v.add(new DERTaggedObject(true, 1, maskGenAlgorithm));
+        }
+        
+        if (!pSourceAlgorithm.equals(DEFAULT_P_SOURCE_ALGORITHM))
+        {
+            v.add(new DERTaggedObject(true, 2, pSourceAlgorithm));
+        }
+        
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java
new file mode 100644
index 0000000..998b7c6
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java
@@ -0,0 +1,186 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+public class RSAPrivateKeyStructure
+    extends ASN1Encodable
+{
+    private int         version;
+    private BigInteger  modulus;
+    private BigInteger  publicExponent;
+    private BigInteger  privateExponent;
+    private BigInteger  prime1;
+    private BigInteger  prime2;
+    private BigInteger  exponent1;
+    private BigInteger  exponent2;
+    private BigInteger  coefficient;
+    private ASN1Sequence otherPrimeInfos = null;
+
+    public static RSAPrivateKeyStructure getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static RSAPrivateKeyStructure getInstance(
+        Object  obj)
+    {
+        if (obj instanceof RSAPrivateKeyStructure)
+        {
+            return (RSAPrivateKeyStructure)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new RSAPrivateKeyStructure((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+    
+    public RSAPrivateKeyStructure(
+        BigInteger  modulus,
+        BigInteger  publicExponent,
+        BigInteger  privateExponent,
+        BigInteger  prime1,
+        BigInteger  prime2,
+        BigInteger  exponent1,
+        BigInteger  exponent2,
+        BigInteger  coefficient)
+    {
+        this.version = 0;
+        this.modulus = modulus;
+        this.publicExponent = publicExponent;
+        this.privateExponent = privateExponent;
+        this.prime1 = prime1;
+        this.prime2 = prime2;
+        this.exponent1 = exponent1;
+        this.exponent2 = exponent2;
+        this.coefficient = coefficient;
+    }
+
+    public RSAPrivateKeyStructure(
+        ASN1Sequence  seq)
+    {
+        Enumeration e = seq.getObjects();
+
+        BigInteger  v = ((DERInteger)e.nextElement()).getValue();
+        if (v.intValue() != 0 && v.intValue() != 1)
+        {
+            throw new IllegalArgumentException("wrong version for RSA private key");
+        }
+
+        version = v.intValue();
+        modulus = ((DERInteger)e.nextElement()).getValue();
+        publicExponent = ((DERInteger)e.nextElement()).getValue();
+        privateExponent = ((DERInteger)e.nextElement()).getValue();
+        prime1 = ((DERInteger)e.nextElement()).getValue();
+        prime2 = ((DERInteger)e.nextElement()).getValue();
+        exponent1 = ((DERInteger)e.nextElement()).getValue();
+        exponent2 = ((DERInteger)e.nextElement()).getValue();
+        coefficient = ((DERInteger)e.nextElement()).getValue();
+        
+        if (e.hasMoreElements())
+        {
+            otherPrimeInfos = (ASN1Sequence)e.nextElement();
+        }
+    }
+
+    public int getVersion()
+    {
+        return version;
+    }
+    
+    public BigInteger getModulus()
+    {
+        return modulus;
+    }
+
+    public BigInteger getPublicExponent()
+    {
+        return publicExponent;
+    }
+
+    public BigInteger getPrivateExponent()
+    {
+        return privateExponent;
+    }
+
+    public BigInteger getPrime1()
+    {
+        return prime1;
+    }
+
+    public BigInteger getPrime2()
+    {
+        return prime2;
+    }
+
+    public BigInteger getExponent1()
+    {
+        return exponent1;
+    }
+
+    public BigInteger getExponent2()
+    {
+        return exponent2;
+    }
+
+    public BigInteger getCoefficient()
+    {
+        return coefficient;
+    }
+
+    /**
+     * This outputs the key in PKCS1v2 format.
+     * <pre>
+     *      RSAPrivateKey ::= SEQUENCE {
+     *                          version Version,
+     *                          modulus INTEGER, -- n
+     *                          publicExponent INTEGER, -- e
+     *                          privateExponent INTEGER, -- d
+     *                          prime1 INTEGER, -- p
+     *                          prime2 INTEGER, -- q
+     *                          exponent1 INTEGER, -- d mod (p-1)
+     *                          exponent2 INTEGER, -- d mod (q-1)
+     *                          coefficient INTEGER, -- (inverse of q) mod p
+     *                          otherPrimeInfos OtherPrimeInfos OPTIONAL
+     *                      }
+     *
+     *      Version ::= INTEGER { two-prime(0), multi(1) }
+     *        (CONSTRAINED BY {-- version must be multi if otherPrimeInfos present --})
+     * </pre>
+     * <p>
+     * This routine is written to output PKCS1 version 2.1, private keys.
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(new DERInteger(version));                       // version
+        v.add(new DERInteger(getModulus()));
+        v.add(new DERInteger(getPublicExponent()));
+        v.add(new DERInteger(getPrivateExponent()));
+        v.add(new DERInteger(getPrime1()));
+        v.add(new DERInteger(getPrime2()));
+        v.add(new DERInteger(getExponent1()));
+        v.add(new DERInteger(getExponent2()));
+        v.add(new DERInteger(getCoefficient()));
+
+        if (otherPrimeInfos != null)
+        {
+            v.add(otherPrimeInfos);
+        }
+        
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java
new file mode 100644
index 0000000..684aabd
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java
@@ -0,0 +1,172 @@
+package org.bouncycastle.asn1.pkcs;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class RSASSAPSSparams
+    extends ASN1Encodable
+{
+    private AlgorithmIdentifier hashAlgorithm;
+    private AlgorithmIdentifier maskGenAlgorithm;
+    private DERInteger          saltLength;
+    private DERInteger          trailerField;
+    
+    // BEGIN android-changed
+    public final static AlgorithmIdentifier DEFAULT_HASH_ALGORITHM = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.THE_ONE);
+    // END android-changed
+    public final static AlgorithmIdentifier DEFAULT_MASK_GEN_FUNCTION = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, DEFAULT_HASH_ALGORITHM);
+    public final static DERInteger          DEFAULT_SALT_LENGTH = new DERInteger(20);
+    public final static DERInteger          DEFAULT_TRAILER_FIELD = new DERInteger(1);
+    
+    public static RSASSAPSSparams getInstance(
+        Object  obj)
+    {
+        if (obj instanceof RSASSAPSSparams)
+        {
+            return (RSASSAPSSparams)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new RSASSAPSSparams((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+    
+    /**
+     * The default version
+     */
+    public RSASSAPSSparams()
+    {
+        hashAlgorithm = DEFAULT_HASH_ALGORITHM;
+        maskGenAlgorithm = DEFAULT_MASK_GEN_FUNCTION;
+        saltLength = DEFAULT_SALT_LENGTH;
+        trailerField = DEFAULT_TRAILER_FIELD;
+    }
+    
+    public RSASSAPSSparams(
+        AlgorithmIdentifier hashAlgorithm,
+        AlgorithmIdentifier maskGenAlgorithm,
+        DERInteger          saltLength,
+        DERInteger          trailerField)
+    {
+        this.hashAlgorithm = hashAlgorithm;
+        this.maskGenAlgorithm = maskGenAlgorithm;
+        this.saltLength = saltLength;
+        this.trailerField = trailerField;
+    }
+    
+    public RSASSAPSSparams(
+        ASN1Sequence seq)
+    {
+        hashAlgorithm = DEFAULT_HASH_ALGORITHM;
+        maskGenAlgorithm = DEFAULT_MASK_GEN_FUNCTION;
+        saltLength = DEFAULT_SALT_LENGTH;
+        trailerField = DEFAULT_TRAILER_FIELD;
+        
+        for (int i = 0; i != seq.size(); i++)
+        {
+            ASN1TaggedObject    o = (ASN1TaggedObject)seq.getObjectAt(i);
+            
+            switch (o.getTagNo())
+            {
+            case 0:
+                hashAlgorithm = AlgorithmIdentifier.getInstance(o, true);
+                break;
+            case 1:
+                maskGenAlgorithm = AlgorithmIdentifier.getInstance(o, true);
+                break;
+            case 2:
+                saltLength = DERInteger.getInstance(o, true);
+                break;
+            case 3:
+                trailerField = DERInteger.getInstance(o, true);
+                break;
+            default:
+                throw new IllegalArgumentException("unknown tag");
+            }
+        }
+    }
+    
+    public AlgorithmIdentifier getHashAlgorithm()
+    {
+        return hashAlgorithm;
+    }
+    
+    public AlgorithmIdentifier getMaskGenAlgorithm()
+    {
+        return maskGenAlgorithm;
+    }
+    
+    public DERInteger getSaltLength()
+    {
+        return saltLength;
+    }
+    
+    public DERInteger getTrailerField()
+    {
+        return trailerField;
+    }
+    
+    /**
+     * <pre>
+     * RSASSA-PSS-params ::= SEQUENCE {
+     *   hashAlgorithm      [0] OAEP-PSSDigestAlgorithms  DEFAULT sha1,
+     *    maskGenAlgorithm   [1] PKCS1MGFAlgorithms  DEFAULT mgf1SHA1,
+     *    saltLength         [2] INTEGER  DEFAULT 20,
+     *    trailerField       [3] TrailerField  DEFAULT trailerFieldBC
+     *  }
+     *
+     * OAEP-PSSDigestAlgorithms    ALGORITHM-IDENTIFIER ::= {
+     *    { OID id-sha1 PARAMETERS NULL   }|
+     *    { OID id-sha256 PARAMETERS NULL }|
+     *    { OID id-sha384 PARAMETERS NULL }|
+     *    { OID id-sha512 PARAMETERS NULL },
+     *    ...  -- Allows for future expansion --
+     * }
+     *
+     * PKCS1MGFAlgorithms    ALGORITHM-IDENTIFIER ::= {
+     *   { OID id-mgf1 PARAMETERS OAEP-PSSDigestAlgorithms },
+     *    ...  -- Allows for future expansion --
+     * }
+     * 
+     * TrailerField ::= INTEGER { trailerFieldBC(1) }
+     * </pre>
+     * @return the asn1 primitive representing the parameters.
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+        
+        if (!hashAlgorithm.equals(DEFAULT_HASH_ALGORITHM))
+        {
+            v.add(new DERTaggedObject(true, 0, hashAlgorithm));
+        }
+        
+        if (!maskGenAlgorithm.equals(DEFAULT_MASK_GEN_FUNCTION))
+        {
+            v.add(new DERTaggedObject(true, 1, maskGenAlgorithm));
+        }
+        
+        if (!saltLength.equals(DEFAULT_SALT_LENGTH))
+        {
+            v.add(new DERTaggedObject(true, 2, saltLength));
+        }
+        
+        if (!trailerField.equals(DEFAULT_TRAILER_FIELD))
+        {
+            v.add(new DERTaggedObject(true, 3, trailerField));
+        }
+        
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/SafeBag.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/SafeBag.java
new file mode 100644
index 0000000..2808d92
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/SafeBag.java
@@ -0,0 +1,78 @@
+package org.bouncycastle.asn1.pkcs;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+public class SafeBag
+    extends ASN1Encodable
+{
+    DERObjectIdentifier         bagId;
+    DERObject                   bagValue;
+    ASN1Set                     bagAttributes;
+
+    public SafeBag(
+        DERObjectIdentifier     oid,
+        DERObject               obj)
+    {
+        this.bagId = oid;
+        this.bagValue = obj;
+        this.bagAttributes = null;
+    }
+
+    public SafeBag(
+        DERObjectIdentifier     oid,
+        DERObject               obj,
+        ASN1Set                 bagAttributes)
+    {
+        this.bagId = oid;
+        this.bagValue = obj;
+        this.bagAttributes = bagAttributes;
+    }
+
+    public SafeBag(
+        ASN1Sequence    seq)
+    {
+        this.bagId = (DERObjectIdentifier)seq.getObjectAt(0);
+        this.bagValue = ((DERTaggedObject)seq.getObjectAt(1)).getObject();
+        if (seq.size() == 3)
+        {
+            this.bagAttributes = (ASN1Set)seq.getObjectAt(2);
+        }
+    }
+
+    public DERObjectIdentifier getBagId()
+    {
+        return bagId;
+    }
+
+    public DERObject getBagValue()
+    {
+        return bagValue;
+    }
+
+    public ASN1Set getBagAttributes()
+    {
+        return bagAttributes;
+    }
+
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(bagId);
+        v.add(new DERTaggedObject(0, bagValue));
+
+        if (bagAttributes != null)
+        {
+            v.add(bagAttributes);
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/SignedData.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/SignedData.java
new file mode 100644
index 0000000..136ad11
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/SignedData.java
@@ -0,0 +1,166 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.BERSequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * a PKCS#7 signed data object.
+ */
+public class SignedData
+    extends ASN1Encodable
+    implements PKCSObjectIdentifiers
+{
+    private DERInteger              version;
+    private ASN1Set                 digestAlgorithms;
+    private ContentInfo             contentInfo;
+    private ASN1Set                 certificates;
+    private ASN1Set                 crls;
+    private ASN1Set                 signerInfos;
+
+    public static SignedData getInstance(
+        Object  o)
+    {
+        if (o instanceof SignedData)
+        {
+            return (SignedData)o;
+        }
+        else if (o instanceof ASN1Sequence)
+        {
+            return new SignedData((ASN1Sequence)o);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory: " + o);
+    }
+
+    public SignedData(
+        DERInteger        _version,
+        ASN1Set           _digestAlgorithms,
+        ContentInfo       _contentInfo,
+        ASN1Set           _certificates,
+        ASN1Set           _crls,
+        ASN1Set           _signerInfos)
+    {
+        version          = _version;
+        digestAlgorithms = _digestAlgorithms;
+        contentInfo      = _contentInfo;
+        certificates     = _certificates;
+        crls             = _crls;
+        signerInfos      = _signerInfos;
+    }
+
+    public SignedData(
+        ASN1Sequence seq)
+    {
+        Enumeration     e = seq.getObjects();
+
+        version = (DERInteger)e.nextElement();
+        digestAlgorithms = ((ASN1Set)e.nextElement());
+        contentInfo = ContentInfo.getInstance(e.nextElement());
+
+        while (e.hasMoreElements())
+        {
+            DERObject o = (DERObject)e.nextElement();
+
+            //
+            // an interesting feature of SignedData is that there appear to be varying implementations...
+            // for the moment we ignore anything which doesn't fit.
+            //
+            if (o instanceof DERTaggedObject)
+            {
+                DERTaggedObject tagged = (DERTaggedObject)o;
+
+                switch (tagged.getTagNo())
+                {
+                case 0:
+                    certificates = ASN1Set.getInstance(tagged, false);
+                    break;
+                case 1:
+                    crls = ASN1Set.getInstance(tagged, false);
+                    break;
+                default:
+                    throw new IllegalArgumentException("unknown tag value " + tagged.getTagNo());
+                }
+            }
+            else
+            {
+                signerInfos = (ASN1Set)o;
+            }
+        }
+    }
+
+    public DERInteger getVersion()
+    {
+        return version;
+    }
+
+    public ASN1Set getDigestAlgorithms()
+    {
+        return digestAlgorithms;
+    }
+
+    public ContentInfo getContentInfo()
+    {
+        return contentInfo;
+    }
+
+    public ASN1Set getCertificates()
+    {
+        return certificates;
+    }
+
+    public ASN1Set getCRLs()
+    {
+        return crls;
+    }
+
+    public ASN1Set getSignerInfos()
+    {
+        return signerInfos;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  SignedData ::= SEQUENCE {
+     *      version Version,
+     *      digestAlgorithms DigestAlgorithmIdentifiers,
+     *      contentInfo ContentInfo,
+     *      certificates
+     *          [0] IMPLICIT ExtendedCertificatesAndCertificates
+     *                   OPTIONAL,
+     *      crls
+     *          [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+     *      signerInfos SignerInfos }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(version);
+        v.add(digestAlgorithms);
+        v.add(contentInfo);
+
+        if (certificates != null)
+        {
+            v.add(new DERTaggedObject(false, 0, certificates));
+        }
+
+        if (crls != null)
+        {
+            v.add(new DERTaggedObject(false, 1, crls));
+        }
+
+        v.add(signerInfos);
+
+        return new BERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/SignerInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/SignerInfo.java
new file mode 100644
index 0000000..8e4ccbb
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/pkcs/SignerInfo.java
@@ -0,0 +1,168 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.*;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * a PKCS#7 signer info object.
+ */
+public class SignerInfo
+    extends ASN1Encodable
+{
+    private DERInteger              version;
+    private IssuerAndSerialNumber   issuerAndSerialNumber;
+    private AlgorithmIdentifier     digAlgorithm;
+    private ASN1Set                 authenticatedAttributes;
+    private AlgorithmIdentifier     digEncryptionAlgorithm;
+    private ASN1OctetString         encryptedDigest;
+    private ASN1Set                 unauthenticatedAttributes;
+
+    public static SignerInfo getInstance(
+        Object  o)
+    {
+        if (o instanceof SignerInfo)
+        {
+            return (SignerInfo)o;
+        }
+        else if (o instanceof ASN1Sequence)
+        {
+            return new SignerInfo((ASN1Sequence)o);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public SignerInfo(
+        DERInteger              version,
+        IssuerAndSerialNumber   issuerAndSerialNumber,
+        AlgorithmIdentifier     digAlgorithm,
+        ASN1Set                 authenticatedAttributes,
+        AlgorithmIdentifier     digEncryptionAlgorithm,
+        ASN1OctetString         encryptedDigest,
+        ASN1Set                 unauthenticatedAttributes)
+    {
+        this.version = version;
+        this.issuerAndSerialNumber = issuerAndSerialNumber;
+        this.digAlgorithm = digAlgorithm;
+        this.authenticatedAttributes = authenticatedAttributes;
+        this.digEncryptionAlgorithm = digEncryptionAlgorithm;
+        this.encryptedDigest = encryptedDigest;
+        this.unauthenticatedAttributes = unauthenticatedAttributes;
+    }
+
+    public SignerInfo(
+        ASN1Sequence seq)
+    {
+        Enumeration     e = seq.getObjects();
+
+        version = (DERInteger)e.nextElement();
+        issuerAndSerialNumber = IssuerAndSerialNumber.getInstance(e.nextElement());
+        digAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement());
+
+        Object obj = e.nextElement();
+
+        if (obj instanceof ASN1TaggedObject)
+        {
+            authenticatedAttributes = ASN1Set.getInstance((ASN1TaggedObject)obj, false);
+
+            digEncryptionAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement());
+        }
+        else
+        {
+            authenticatedAttributes = null;
+            digEncryptionAlgorithm = AlgorithmIdentifier.getInstance(obj);
+        }
+
+        encryptedDigest = DEROctetString.getInstance(e.nextElement());
+
+        if (e.hasMoreElements())
+        {
+            unauthenticatedAttributes = ASN1Set.getInstance((ASN1TaggedObject)e.nextElement(), false);
+        }
+        else
+        {
+            unauthenticatedAttributes = null;
+        }
+    }
+
+    public DERInteger getVersion()
+    {
+        return version;
+    }
+
+    public IssuerAndSerialNumber getIssuerAndSerialNumber()
+    {
+        return issuerAndSerialNumber;
+    }
+
+    public ASN1Set getAuthenticatedAttributes()
+    {
+        return authenticatedAttributes;
+    }
+
+    public AlgorithmIdentifier getDigestAlgorithm()
+    {
+        return digAlgorithm;
+    }
+
+    public ASN1OctetString getEncryptedDigest()
+    {
+        return encryptedDigest;
+    }
+
+    public AlgorithmIdentifier getDigestEncryptionAlgorithm()
+    {
+        return digEncryptionAlgorithm;
+    }
+
+    public ASN1Set getUnauthenticatedAttributes()
+    {
+        return unauthenticatedAttributes;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  SignerInfo ::= SEQUENCE {
+     *      version Version,
+     *      issuerAndSerialNumber IssuerAndSerialNumber,
+     *      digestAlgorithm DigestAlgorithmIdentifier,
+     *      authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
+     *      digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
+     *      encryptedDigest EncryptedDigest,
+     *      unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
+     *  }
+     *
+     *  EncryptedDigest ::= OCTET STRING
+     *
+     *  DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+     *
+     *  DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(version);
+        v.add(issuerAndSerialNumber);
+        v.add(digAlgorithm);
+
+        if (authenticatedAttributes != null)
+        {
+            v.add(new DERTaggedObject(false, 0, authenticatedAttributes));
+        }
+
+        v.add(digEncryptionAlgorithm);
+        v.add(encryptedDigest);
+
+        if (unauthenticatedAttributes != null)
+        {
+            v.add(new DERTaggedObject(false, 1, unauthenticatedAttributes));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java b/libcore/security/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java
new file mode 100644
index 0000000..58098e1
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java
@@ -0,0 +1,18 @@
+package org.bouncycastle.asn1.teletrust;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+public interface TeleTrusTObjectIdentifiers
+{
+    static final String teleTrusTAlgorithm = "1.3.36.3";
+
+    static final DERObjectIdentifier    ripemd160           = new DERObjectIdentifier(teleTrusTAlgorithm + ".2.1");
+    static final DERObjectIdentifier    ripemd128           = new DERObjectIdentifier(teleTrusTAlgorithm + ".2.2");
+    static final DERObjectIdentifier    ripemd256           = new DERObjectIdentifier(teleTrusTAlgorithm + ".2.3");
+
+    static final String teleTrusTRSAsignatureAlgorithm = teleTrusTAlgorithm + ".3.1";
+
+    static final DERObjectIdentifier    rsaSignatureWithripemd160           = new DERObjectIdentifier(teleTrusTRSAsignatureAlgorithm + ".2");
+    static final DERObjectIdentifier    rsaSignatureWithripemd128           = new DERObjectIdentifier(teleTrusTRSAsignatureAlgorithm + ".3");
+    static final DERObjectIdentifier    rsaSignatureWithripemd256           = new DERObjectIdentifier(teleTrusTRSAsignatureAlgorithm + ".4");
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/tsp/Accuracy.java b/libcore/security/src/main/java/org/bouncycastle/asn1/tsp/Accuracy.java
new file mode 100644
index 0000000..18f4c15
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/tsp/Accuracy.java
@@ -0,0 +1,174 @@
+package org.bouncycastle.asn1.tsp;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObject;
+
+
+public class Accuracy
+    extends ASN1Encodable
+{
+    DERInteger seconds;
+
+    DERInteger millis;
+
+    DERInteger micros;
+
+    // constantes
+    protected static final int MIN_MILLIS = 1;
+
+    protected static final int MAX_MILLIS = 999;
+
+    protected static final int MIN_MICROS = 1;
+
+    protected static final int MAX_MICROS = 999;
+
+    protected Accuracy()
+    {
+    }
+
+    public Accuracy(
+        DERInteger seconds,
+        DERInteger millis,
+        DERInteger micros)
+    {
+        this.seconds = seconds;
+
+        //Verifications
+        if (millis != null
+                && (millis.getValue().intValue() < MIN_MILLIS || millis
+                        .getValue().intValue() > MAX_MILLIS))
+        {
+            throw new IllegalArgumentException(
+                    "Invalid millis field : not in (1..999)");
+        }
+        else
+        {
+            this.millis = millis;
+        }
+
+        if (micros != null
+                && (micros.getValue().intValue() < MIN_MICROS || micros
+                        .getValue().intValue() > MAX_MICROS))
+        {
+            throw new IllegalArgumentException(
+                    "Invalid micros field : not in (1..999)");
+        }
+        else
+        {
+            this.micros = micros;
+        }
+
+    }
+
+    public Accuracy(ASN1Sequence seq)
+    {
+        seconds = null;
+        millis = null;
+        micros = null;
+
+        for (int i = 0; i < seq.size(); i++)
+        {
+            // seconds
+            if (seq.getObjectAt(i) instanceof DERInteger)
+            {
+                seconds = (DERInteger) seq.getObjectAt(i);
+            }
+            else if (seq.getObjectAt(i) instanceof DERTaggedObject)
+            {
+                DERTaggedObject extra = (DERTaggedObject) seq.getObjectAt(i);
+
+                switch (extra.getTagNo())
+                {
+                case 0:
+                    millis = DERInteger.getInstance(extra, false);
+                    if (millis.getValue().intValue() < MIN_MILLIS
+                            || millis.getValue().intValue() > MAX_MILLIS)
+                    {
+                        throw new IllegalArgumentException(
+                                "Invalid millis field : not in (1..999).");
+                    }
+                    break;
+                case 1:
+                    micros = DERInteger.getInstance(extra, false);
+                    if (micros.getValue().intValue() < MIN_MICROS
+                            || micros.getValue().intValue() > MAX_MICROS)
+                    {
+                        throw new IllegalArgumentException(
+                                "Invalid micros field : not in (1..999).");
+                    }
+                    break;
+                default:
+                    throw new IllegalArgumentException("Invalig tag number");
+                }
+            }
+        }
+    }
+
+    public static Accuracy getInstance(Object o)
+    {
+        if (o == null || o instanceof Accuracy)
+        {
+            return (Accuracy) o;
+        }
+        else if (o instanceof ASN1Sequence)
+        {
+            return new Accuracy((ASN1Sequence) o);
+        }
+
+        throw new IllegalArgumentException(
+                "Unknown object in 'Accuracy' factory : "
+                        + o.getClass().getName() + ".");
+    }
+
+    public DERInteger getSeconds()
+    {
+        return seconds;
+    }
+
+    public DERInteger getMillis()
+    {
+        return millis;
+    }
+
+    public DERInteger getMicros()
+    {
+        return micros;
+    }
+
+    /**
+     * <pre>
+     * Accuracy ::= SEQUENCE {
+     *             seconds        INTEGER              OPTIONAL,
+     *             millis     [0] INTEGER  (1..999)    OPTIONAL,
+     *             micros     [1] INTEGER  (1..999)    OPTIONAL
+     *             }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+
+        ASN1EncodableVector v = new ASN1EncodableVector();
+        
+        if (seconds != null)
+        {
+            v.add(seconds);
+        }
+        
+        if (millis != null)
+        {
+            v.add(new DERTaggedObject(false, 0, millis));
+        }
+        
+        if (micros != null)
+        {
+            v.add(new DERTaggedObject(false, 1, micros));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/tsp/MessageImprint.java b/libcore/security/src/main/java/org/bouncycastle/asn1/tsp/MessageImprint.java
new file mode 100644
index 0000000..46b8dc1
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/tsp/MessageImprint.java
@@ -0,0 +1,77 @@
+package org.bouncycastle.asn1.tsp;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class MessageImprint
+    extends ASN1Encodable
+{
+    AlgorithmIdentifier hashAlgorithm;
+    byte[]              hashedMessage;
+    
+    /**
+     * @param o
+     * @return a MessageImprint object.
+     */
+    public static MessageImprint getInstance(Object o)
+    {
+        if (o == null || o instanceof MessageImprint)
+        {
+            return (MessageImprint)o;
+        }
+        else if (o instanceof ASN1Sequence)
+        {
+            return new MessageImprint((ASN1Sequence)o);
+        }
+        
+        throw new IllegalArgumentException("Bad object in factory.");
+    }
+    
+    public MessageImprint(
+        ASN1Sequence seq)
+    {
+        this.hashAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0));
+        this.hashedMessage = ASN1OctetString.getInstance(seq.getObjectAt(1)).getOctets();
+    }
+    
+    public MessageImprint(
+        AlgorithmIdentifier hashAlgorithm,
+        byte[]              hashedMessage)
+    {
+        this.hashAlgorithm = hashAlgorithm;
+        this.hashedMessage = hashedMessage;
+    }
+    
+    public AlgorithmIdentifier getHashAlgorithm()
+    {
+        return hashAlgorithm;
+    }
+    
+    public byte[] getHashedMessage()
+    {
+        return hashedMessage;
+    }
+    
+    /**
+     * <pre>
+     *    MessageImprint ::= SEQUENCE  {
+     *       hashAlgorithm                AlgorithmIdentifier,
+     *       hashedMessage                OCTET STRING  }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(hashAlgorithm);
+        v.add(new DEROctetString(hashedMessage));
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/tsp/TSTInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/tsp/TSTInfo.java
new file mode 100644
index 0000000..e81ea3a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/tsp/TSTInfo.java
@@ -0,0 +1,256 @@
+package org.bouncycastle.asn1.tsp;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERBoolean;
+import org.bouncycastle.asn1.DEREncodableVector;
+import org.bouncycastle.asn1.DERGeneralizedTime;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.X509Extensions;
+
+public class TSTInfo
+    extends ASN1Encodable
+{
+    DERInteger version;
+
+    DERObjectIdentifier tsaPolicyId;
+
+    MessageImprint messageImprint;
+
+    DERInteger serialNumber;
+
+    DERGeneralizedTime genTime;
+
+    Accuracy accuracy;
+
+    DERBoolean ordering;
+
+    DERInteger nonce;
+
+    GeneralName tsa;
+
+    X509Extensions extensions;
+
+    public static TSTInfo getInstance(Object o)
+    {
+        if (o == null || o instanceof TSTInfo)
+        {
+            return (TSTInfo) o;
+        }
+        else if (o instanceof ASN1Sequence)
+        {
+            return new TSTInfo((ASN1Sequence) o);
+        }
+        else if (o instanceof ASN1OctetString)
+        {
+            try
+            {
+                return getInstance(new ASN1InputStream(((ASN1OctetString)o).getOctets()).readObject());
+            }
+            catch (IOException ioEx)
+            {
+                throw new IllegalArgumentException(
+                        "Bad object format in 'TSTInfo' factory.");
+            }
+        }
+
+        throw new IllegalArgumentException(
+                "Unknown object in 'TSTInfo' factory : "
+                        + o.getClass().getName() + ".");
+    }
+
+    public TSTInfo(ASN1Sequence seq)
+    {
+        Enumeration e = seq.getObjects();
+
+        // version
+        version = DERInteger.getInstance(e.nextElement());
+
+        // tsaPolicy
+        tsaPolicyId = DERObjectIdentifier.getInstance(e.nextElement());
+
+        // messageImprint
+        messageImprint = MessageImprint.getInstance(e.nextElement());
+
+        // serialNumber
+        serialNumber = DERInteger.getInstance(e.nextElement());
+
+        // genTime
+        genTime = DERGeneralizedTime.getInstance(e.nextElement());
+
+        // default for ordering
+        // BEGIN android-changed
+        ordering = DERBoolean.FALSE;
+        // END android-changed
+        
+        while (e.hasMoreElements())
+        {
+            DERObject o = (DERObject) e.nextElement();
+
+            if (o instanceof ASN1TaggedObject)
+            {
+                DERTaggedObject tagged = (DERTaggedObject) o;
+
+                switch (tagged.getTagNo())
+                {
+                case 0:
+                    tsa = GeneralName.getInstance(tagged, true);
+                    break;
+                case 1:
+                    extensions = X509Extensions.getInstance(tagged, false);
+                    break;
+                default:
+                    throw new IllegalArgumentException("Unknown tag value " + tagged.getTagNo());
+                }
+            }
+            else if (o instanceof DERSequence)
+            {
+                accuracy = Accuracy.getInstance(o);
+            }
+            else if (o instanceof DERBoolean)
+            {
+                ordering = DERBoolean.getInstance(o);
+            }
+            else if (o instanceof DERInteger)
+            {
+                nonce = DERInteger.getInstance(o);
+            }
+
+        }
+    }
+
+    public TSTInfo(DERObjectIdentifier tsaPolicyId, MessageImprint messageImprint,
+            DERInteger serialNumber, DERGeneralizedTime genTime,
+            Accuracy accuracy, DERBoolean ordering, DERInteger nonce,
+            GeneralName tsa, X509Extensions extensions)
+    {
+        version = new DERInteger(1);
+        this.tsaPolicyId = tsaPolicyId;
+        this.messageImprint = messageImprint;
+        this.serialNumber = serialNumber;
+        this.genTime = genTime;
+
+        this.accuracy = accuracy;
+        this.ordering = ordering;
+        this.nonce = nonce;
+        this.tsa = tsa;
+        this.extensions = extensions;
+    }
+
+    public MessageImprint getMessageImprint()
+    {
+        return messageImprint;
+    }
+
+    public DERObjectIdentifier getPolicy()
+    {
+        return tsaPolicyId;
+    }
+
+    public DERInteger getSerialNumber()
+    {
+        return serialNumber;
+    }
+
+    public Accuracy getAccuracy()
+    {
+        return accuracy;
+    }
+
+    public DERGeneralizedTime getGenTime()
+    {
+        return genTime;
+    }
+
+    public DERBoolean getOrdering()
+    {
+        return ordering;
+    }
+
+    public DERInteger getNonce()
+    {
+        return nonce;
+    }
+
+    public GeneralName getTsa()
+    {
+        return tsa;
+    }
+
+    public X509Extensions getExtensions()
+    {
+        return extensions;
+    }
+
+    /**
+     * <pre>
+     * 
+     *     TSTInfo ::= SEQUENCE  {
+     *        version                      INTEGER  { v1(1) },
+     *        policy                       TSAPolicyId,
+     *        messageImprint               MessageImprint,
+     *          -- MUST have the same value as the similar field in
+     *          -- TimeStampReq
+     *        serialNumber                 INTEGER,
+     *         -- Time-Stamping users MUST be ready to accommodate integers
+     *         -- up to 160 bits.
+     *        genTime                      GeneralizedTime,
+     *        accuracy                     Accuracy                 OPTIONAL,
+     *        ordering                     BOOLEAN             DEFAULT FALSE,
+     *        nonce                        INTEGER                  OPTIONAL,
+     *          -- MUST be present if the similar field was present
+     *          -- in TimeStampReq.  In that case it MUST have the same value.
+     *        tsa                          [0] GeneralName          OPTIONAL,
+     *        extensions                   [1] IMPLICIT Extensions   OPTIONAL  }
+     * 
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        DEREncodableVector seq = new DEREncodableVector();
+        seq.add(version);
+
+        seq.add(tsaPolicyId);
+        seq.add(messageImprint);
+        seq.add(serialNumber);
+        seq.add(genTime);
+
+        if (accuracy != null)
+        {
+            seq.add(accuracy);
+        }
+        
+        if (ordering != null && ordering.isTrue())
+        {
+            seq.add(ordering);
+        }
+        
+        if (nonce != null)
+        {
+            seq.add(nonce);
+        }
+        
+        if (tsa != null)
+        {
+            seq.add(new DERTaggedObject(true, 0, tsa));
+        }
+        
+        if (extensions != null)
+        {
+            seq.add(new DERTaggedObject(false, 1, extensions));
+        }
+
+        return new DERSequence(seq);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/tsp/TimeStampReq.java b/libcore/security/src/main/java/org/bouncycastle/asn1/tsp/TimeStampReq.java
new file mode 100644
index 0000000..46565e7
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/tsp/TimeStampReq.java
@@ -0,0 +1,181 @@
+package org.bouncycastle.asn1.tsp;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERBoolean;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x509.X509Extensions;
+
+public class TimeStampReq
+    extends ASN1Encodable
+{
+    DERInteger version;
+
+    MessageImprint messageImprint;
+
+    DERObjectIdentifier tsaPolicy;
+
+    DERInteger nonce;
+
+    DERBoolean certReq;
+
+    X509Extensions extensions;
+
+    public static TimeStampReq getInstance(Object o)
+    {
+        if (o == null || o instanceof TimeStampReq)
+        {
+            return (TimeStampReq) o;
+        }
+        else if (o instanceof ASN1Sequence)
+        {
+            return new TimeStampReq((ASN1Sequence) o);
+        }
+
+        throw new IllegalArgumentException(
+                "Unknown object in 'TimeStampReq' factory : "
+                        + o.getClass().getName() + ".");
+    }
+
+    public TimeStampReq(ASN1Sequence seq)
+    {
+        int nbObjects = seq.size();
+
+        int seqStart = 0;
+
+        // version
+        version = DERInteger.getInstance(seq.getObjectAt(seqStart));
+
+        seqStart++;
+
+        // messageImprint
+        messageImprint = MessageImprint.getInstance(seq.getObjectAt(seqStart));
+
+        seqStart++;
+
+        for (int opt = seqStart; opt < nbObjects; opt++)
+        {
+            // tsaPolicy
+            if (seq.getObjectAt(opt) instanceof DERObjectIdentifier)
+            {
+                tsaPolicy = DERObjectIdentifier.getInstance(seq.getObjectAt(opt));
+            }
+            // nonce
+            else if (seq.getObjectAt(opt) instanceof DERInteger)
+            {
+                nonce = DERInteger.getInstance(seq.getObjectAt(opt));
+            }
+            // certReq
+            else if (seq.getObjectAt(opt) instanceof DERBoolean)
+            {
+                certReq = DERBoolean.getInstance(seq.getObjectAt(opt));
+            }
+            // extensions
+            else if (seq.getObjectAt(opt) instanceof ASN1TaggedObject)
+            {
+                ASN1TaggedObject    tagged = (ASN1TaggedObject)seq.getObjectAt(opt);
+                if (tagged.getTagNo() == 0)
+                {
+                    extensions = X509Extensions.getInstance(tagged, false);
+                }
+            }
+        }
+    }
+
+    public TimeStampReq(
+        MessageImprint      messageImprint,
+        DERObjectIdentifier tsaPolicy,
+        DERInteger          nonce,
+        DERBoolean          certReq,
+        X509Extensions      extensions)
+    {
+        // default
+        version = new DERInteger(1);
+
+        this.messageImprint = messageImprint;
+        this.tsaPolicy = tsaPolicy;
+        this.nonce = nonce;
+        this.certReq = certReq;
+        this.extensions = extensions;
+    }
+
+    public DERInteger getVersion()
+    {
+        return version;
+    }
+
+    public MessageImprint getMessageImprint()
+    {
+        return messageImprint;
+    }
+
+    public DERObjectIdentifier getReqPolicy()
+    {
+        return tsaPolicy;
+    }
+
+    public DERInteger getNonce()
+    {
+        return nonce;
+    }
+
+    public DERBoolean getCertReq()
+    {
+        return certReq;
+    }
+
+    public X509Extensions getExtensions()
+    {
+        return extensions;
+    }
+
+    /**
+     * <pre>
+     * TimeStampReq ::= SEQUENCE  {
+     *  version                      INTEGER  { v1(1) },
+     *  messageImprint               MessageImprint,
+     *    --a hash algorithm OID and the hash value of the data to be
+     *    --time-stamped
+     *  reqPolicy             TSAPolicyId              OPTIONAL,
+     *  nonce                 INTEGER                  OPTIONAL,
+     *  certReq               BOOLEAN                  DEFAULT FALSE,
+     *  extensions            [0] IMPLICIT Extensions  OPTIONAL
+     * }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+        
+        v.add(version);
+        v.add(messageImprint);
+        
+        if (tsaPolicy != null)
+        {
+            v.add(tsaPolicy);
+        }
+        
+        if (nonce != null)
+        {
+            v.add(nonce);
+        }
+        
+        if (certReq != null && certReq.isTrue())
+        {
+            v.add(certReq);
+        }
+        
+        if (extensions != null)
+        {
+            v.add(new DERTaggedObject(false, 0, extensions));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/tsp/TimeStampResp.java b/libcore/security/src/main/java/org/bouncycastle/asn1/tsp/TimeStampResp.java
new file mode 100644
index 0000000..f5bfa7e
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/tsp/TimeStampResp.java
@@ -0,0 +1,86 @@
+package org.bouncycastle.asn1.tsp;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.cms.ContentInfo;
+import org.bouncycastle.asn1.cmp.PKIStatusInfo;
+
+
+public class TimeStampResp
+    extends ASN1Encodable
+{
+    PKIStatusInfo pkiStatusInfo;
+
+    ContentInfo timeStampToken;
+
+    public static TimeStampResp getInstance(Object o)
+    {
+        if (o == null || o instanceof TimeStampResp)
+        {
+            return (TimeStampResp) o;
+        }
+        else if (o instanceof ASN1Sequence)
+        {
+            return new TimeStampResp((ASN1Sequence) o);
+        }
+
+        throw new IllegalArgumentException(
+                "unknown object in 'TimeStampResp' factory : "
+                        + o.getClass().getName() + ".");
+    }
+
+    public TimeStampResp(ASN1Sequence seq)
+    {
+
+        Enumeration e = seq.getObjects();
+
+        // status
+        pkiStatusInfo = PKIStatusInfo.getInstance(e.nextElement());
+
+        if (e.hasMoreElements())
+        {
+            timeStampToken = ContentInfo.getInstance(e.nextElement());
+        }
+    }
+
+    public TimeStampResp(PKIStatusInfo pkiStatusInfo, ContentInfo timeStampToken)
+    {
+        this.pkiStatusInfo = pkiStatusInfo;
+        this.timeStampToken = timeStampToken;
+    }
+
+    public PKIStatusInfo getStatus()
+    {
+        return pkiStatusInfo;
+    }
+
+    public ContentInfo getTimeStampToken()
+    {
+        return timeStampToken;
+    }
+
+    /**
+     * <pre>
+     * TimeStampResp ::= SEQUENCE  {
+     *   status                  PKIStatusInfo,
+     *   timeStampToken          TimeStampToken     OPTIONAL  }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+        
+        v.add(pkiStatusInfo);
+        if (timeStampToken != null)
+        {
+            v.add(timeStampToken);
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java b/libcore/security/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java
new file mode 100644
index 0000000..97dca60
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java
@@ -0,0 +1,292 @@
+package org.bouncycastle.asn1.util;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.*;
+import org.bouncycastle.util.encoders.Hex;
+
+public class ASN1Dump
+{
+    private static String  TAB = "    ";
+
+    /**
+     * dump a DER object as a formatted string with indentation
+     *
+     * @param obj the DERObject to be dumped out.
+     */
+    static String _dumpAsString(
+        String      indent,
+        DERObject   obj)
+    {
+        if (obj instanceof ASN1Sequence)
+        {
+            StringBuffer    buf = new StringBuffer();
+            Enumeration     e = ((ASN1Sequence)obj).getObjects();
+            String          tab = indent + TAB;
+
+            buf.append(indent);
+            if (obj instanceof BERConstructedSequence)
+            {
+                buf.append("BER ConstructedSequence");
+            }
+            else if (obj instanceof DERConstructedSequence)
+            {
+                buf.append("DER ConstructedSequence");
+            }
+            else if (obj instanceof BERSequence)
+            {
+                buf.append("BER Sequence");
+            }
+            else if (obj instanceof DERSequence)
+            {
+                buf.append("DER Sequence");
+            }
+            else
+            {
+                buf.append("Sequence");
+            }
+
+            buf.append(System.getProperty("line.separator"));
+
+            while (e.hasMoreElements())
+            {
+                Object  o = e.nextElement();
+
+                // BEGIN android-changed
+                if (o == null || o.equals(DERNull.THE_ONE))
+                {
+                    buf.append(tab);
+                    buf.append("NULL");
+                    buf.append(System.getProperty("line.separator"));
+                }
+                else if (o instanceof DERObject)
+                {
+                    buf.append(_dumpAsString(tab, (DERObject)o));
+                }
+                else
+                {
+                    buf.append(_dumpAsString(tab, ((DEREncodable)o).getDERObject()));
+                }
+                // END android-changed
+            }
+            return buf.toString();
+        }
+        else if (obj instanceof DERTaggedObject)
+        {
+            StringBuffer    buf = new StringBuffer();
+            String          tab = indent + TAB;
+
+            buf.append(indent);
+            if (obj instanceof BERTaggedObject)
+            {
+                buf.append("BER Tagged [");
+            }
+            else
+            {
+                buf.append("Tagged [");
+            }
+
+            DERTaggedObject o = (DERTaggedObject)obj;
+
+            buf.append(Integer.toString(o.getTagNo()));
+            buf.append(']');
+
+            if (!o.isExplicit())
+            {
+                buf.append(" IMPLICIT ");
+            }
+
+            buf.append(System.getProperty("line.separator"));
+
+            if (o.isEmpty())
+            {
+                buf.append(tab);
+                buf.append("EMPTY");
+                buf.append(System.getProperty("line.separator"));
+            }
+            else
+            {
+                buf.append(_dumpAsString(tab, o.getObject()));
+            }
+
+            return buf.toString();
+        }
+        else if (obj instanceof DERConstructedSet)
+        {
+            StringBuffer    buf = new StringBuffer();
+            Enumeration     e = ((ASN1Set)obj).getObjects();
+            String          tab = indent + TAB;
+
+            buf.append(indent);
+            buf.append("ConstructedSet");
+            buf.append(System.getProperty("line.separator"));
+
+            while (e.hasMoreElements())
+            {
+                Object  o = e.nextElement();
+
+                if (o == null)
+                {
+                    buf.append(tab);
+                    buf.append("NULL");
+                    buf.append(System.getProperty("line.separator"));
+                }
+                else if (o instanceof DERObject)
+                {
+                    buf.append(_dumpAsString(tab, (DERObject)o));
+                }
+                else
+                {
+                    buf.append(_dumpAsString(tab, ((DEREncodable)o).getDERObject()));
+                }
+            }
+            return buf.toString();
+        }
+        else if (obj instanceof BERSet)
+        {
+            StringBuffer    buf = new StringBuffer();
+            Enumeration     e = ((ASN1Set)obj).getObjects();
+            String          tab = indent + TAB;
+
+            buf.append(indent);
+            buf.append("BER Set");
+            buf.append(System.getProperty("line.separator"));
+
+            while (e.hasMoreElements())
+            {
+                Object  o = e.nextElement();
+
+                if (o == null)
+                {
+                    buf.append(tab);
+                    buf.append("NULL");
+                    buf.append(System.getProperty("line.separator"));
+                }
+                else if (o instanceof DERObject)
+                {
+                    buf.append(_dumpAsString(tab, (DERObject)o));
+                }
+                else
+                {
+                    buf.append(_dumpAsString(tab, ((DEREncodable)o).getDERObject()));
+                }
+            }
+            return buf.toString();
+        }
+        else if (obj instanceof DERSet)
+        {
+            StringBuffer    buf = new StringBuffer();
+            Enumeration     e = ((ASN1Set)obj).getObjects();
+            String          tab = indent + TAB;
+
+            buf.append(indent);
+            buf.append("DER Set");
+            buf.append(System.getProperty("line.separator"));
+
+            while (e.hasMoreElements())
+            {
+                Object  o = e.nextElement();
+
+                if (o == null)
+                {
+                    buf.append(tab);
+                    buf.append("NULL");
+                    buf.append(System.getProperty("line.separator"));
+                }
+                else if (o instanceof DERObject)
+                {
+                    buf.append(_dumpAsString(tab, (DERObject)o));
+                }
+                else
+                {
+                    buf.append(_dumpAsString(tab, ((DEREncodable)o).getDERObject()));
+                }
+            }
+            return buf.toString();
+        }
+        else if (obj instanceof DERObjectIdentifier)
+        {
+            return indent + "ObjectIdentifier(" + ((DERObjectIdentifier)obj).getId() + ")" + System.getProperty("line.separator");
+        }
+        else if (obj instanceof DERBoolean)
+        {
+            return indent + "Boolean(" + ((DERBoolean)obj).isTrue() + ")" + System.getProperty("line.separator");
+        }
+        else if (obj instanceof DERInteger)
+        {
+            return indent + "Integer(" + ((DERInteger)obj).getValue() + ")" + System.getProperty("line.separator");
+        }
+        else if (obj instanceof BERConstructedOctetString)
+        {
+            return indent + "BER Constructed Octet String" + "[" + ((ASN1OctetString)obj).getOctets().length + "] " + System.getProperty("line.separator");
+        }
+        else if (obj instanceof DEROctetString)
+        {
+            return indent + "DER Octet String" + "[" + ((ASN1OctetString)obj).getOctets().length + "] " + System.getProperty("line.separator");
+        }
+        else if (obj instanceof DERBitString)
+        {
+            return indent + "DER Bit String" + "[" + ((DERBitString)obj).getBytes().length + ", " + ((DERBitString)obj).getPadBits() + "] " + System.getProperty("line.separator");
+        }
+        else if (obj instanceof DERIA5String)
+        {
+            return indent + "IA5String(" + ((DERIA5String)obj).getString() + ") " + System.getProperty("line.separator");
+        }
+        else if (obj instanceof DERUTF8String)
+        {
+            return indent + "UTF8String(" + ((DERUTF8String)obj).getString() + ") " + System.getProperty("line.separator");
+        }
+        else if (obj instanceof DERPrintableString)
+        {
+            return indent + "PrintableString(" + ((DERPrintableString)obj).getString() + ") " + System.getProperty("line.separator");
+        }
+        else if (obj instanceof DERVisibleString)
+        {
+            return indent + "VisibleString(" + ((DERVisibleString)obj).getString() + ") " + System.getProperty("line.separator");
+        }
+        else if (obj instanceof DERBMPString)
+        {
+            return indent + "BMPString(" + ((DERBMPString)obj).getString() + ") " + System.getProperty("line.separator");
+        }
+        else if (obj instanceof DERT61String)
+        {
+            return indent + "T61String(" + ((DERT61String)obj).getString() + ") " + System.getProperty("line.separator");
+        }
+        else if (obj instanceof DERUTCTime)
+        {
+            return indent + "UTCTime(" + ((DERUTCTime)obj).getTime() + ") " + System.getProperty("line.separator");
+        }
+        else if (obj instanceof DERGeneralizedTime)
+        {
+            return indent + "GeneralizedTime(" + ((DERGeneralizedTime)obj).getTime() + ") " + System.getProperty("line.separator");
+        }
+        else if (obj instanceof DERUnknownTag)
+        {
+            return indent + "Unknown " + Integer.toString(((DERUnknownTag)obj).getTag(), 16) + " " + new String(Hex.encode(((DERUnknownTag)obj).getData())) + System.getProperty("line.separator");
+        }
+        else
+        {
+            return indent + obj.toString() + System.getProperty("line.separator");
+        }
+    }
+
+    /**
+     * dump out a DER object as a formatted string
+     *
+     * @param obj the DERObject to be dumped out.
+     */
+    public static String dumpAsString(
+        Object   obj)
+    {
+        if (obj instanceof DERObject)
+        {
+            return _dumpAsString("", (DERObject)obj);
+        }
+        else if (obj instanceof DEREncodable)
+        {
+            return _dumpAsString("", ((DEREncodable)obj).getDERObject());
+        }
+
+        return "unknown object type " + obj.toString();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/util/DERDump.java b/libcore/security/src/main/java/org/bouncycastle/asn1/util/DERDump.java
new file mode 100644
index 0000000..e9d307a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/util/DERDump.java
@@ -0,0 +1,33 @@
+package org.bouncycastle.asn1.util;
+
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERObject;
+
+/**
+ * @deprecated use ASN1Dump.
+ */
+public class DERDump
+    extends ASN1Dump
+{
+    /**
+     * dump out a DER object as a formatted string
+     *
+     * @param obj the DERObject to be dumped out.
+     */
+    public static String dumpAsString(
+        DERObject   obj)
+    {
+        return _dumpAsString("", obj);
+    }
+
+    /**
+     * dump out a DER object as a formatted string
+     *
+     * @param obj the DERObject to be dumped out.
+     */
+    public static String dumpAsString(
+        DEREncodable   obj)
+    {
+        return _dumpAsString("", obj.getDERObject());
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/util/Dump.java b/libcore/security/src/main/java/org/bouncycastle/asn1/util/Dump.java
new file mode 100644
index 0000000..27a37f3
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/util/Dump.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.asn1.util;
+
+import java.io.FileInputStream;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+
+public class Dump
+{
+    public static void main(
+        String args[])
+        throws Exception
+    {
+        FileInputStream fIn = new FileInputStream(args[0]);
+        ASN1InputStream bIn = new ASN1InputStream(fIn);
+        Object          obj = null;
+
+        while ((obj = bIn.readObject()) != null)
+        {
+            System.out.println(ASN1Dump.dumpAsString(obj));
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AccessDescription.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AccessDescription.java
new file mode 100644
index 0000000..ae13f55
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AccessDescription.java
@@ -0,0 +1,98 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+
+/**
+ * The AccessDescription object.
+ * <pre>
+ * AccessDescription  ::=  SEQUENCE {
+ *       accessMethod          OBJECT IDENTIFIER,
+ *       accessLocation        GeneralName  }
+ * </pre>
+ */
+public class AccessDescription
+    extends ASN1Encodable
+{
+    public final static DERObjectIdentifier id_ad_caIssuers = new DERObjectIdentifier("1.3.6.1.5.5.7.48.2");
+    
+    public final static DERObjectIdentifier id_ad_ocsp = new DERObjectIdentifier("1.3.6.1.5.5.7.48.1");
+        
+    DERObjectIdentifier accessMethod = null;
+    GeneralName accessLocation = null;
+
+    public static AccessDescription getInstance(
+        Object  obj)
+    {
+        if (obj instanceof AccessDescription)
+        {
+            return (AccessDescription)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new AccessDescription((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+ 
+    public AccessDescription(
+        ASN1Sequence   seq)
+    {
+        if (seq.size() != 2) 
+        {
+            throw new IllegalArgumentException("wrong number of elements in inner sequence");
+        }
+        
+        accessMethod = DERObjectIdentifier.getInstance(seq.getObjectAt(0));
+        accessLocation = GeneralName.getInstance(seq.getObjectAt(1));
+    }
+
+    /**
+     * create an AccessDescription with the oid and location provided.
+     */
+    public AccessDescription(
+        DERObjectIdentifier oid,
+        GeneralName location)
+    {
+        accessMethod = oid;
+        accessLocation = location;
+    }
+
+    /**
+     * 
+     * @return the access method.
+     */
+    public DERObjectIdentifier getAccessMethod()
+    {
+        return accessMethod;
+    }
+    
+    /**
+     * 
+     * @return the access location
+     */
+    public GeneralName getAccessLocation()
+    {
+        return accessLocation;
+    }
+    
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector accessDescription  = new ASN1EncodableVector();
+        
+        accessDescription.add(accessMethod);
+        accessDescription.add(accessLocation);
+
+        return new DERSequence(accessDescription);
+    }
+
+    public String toString()
+    {
+        return ("AccessDescription: Oid(" + this.accessMethod.getId() + ")");
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java
new file mode 100644
index 0000000..501dc9c
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java
@@ -0,0 +1,126 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+
+public class AlgorithmIdentifier
+    extends ASN1Encodable
+{
+    private DERObjectIdentifier objectId;
+    private DEREncodable        parameters;
+    private boolean             parametersDefined = false;
+
+    public static AlgorithmIdentifier getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+    
+    public static AlgorithmIdentifier getInstance(
+        Object  obj)
+    {
+        if (obj== null || obj instanceof AlgorithmIdentifier)
+        {
+            return (AlgorithmIdentifier)obj;
+        }
+        
+        if (obj instanceof DERObjectIdentifier)
+        {
+            return new AlgorithmIdentifier((DERObjectIdentifier)obj);
+        }
+
+        if (obj instanceof String)
+        {
+            return new AlgorithmIdentifier((String)obj);
+        }
+
+        if (obj instanceof ASN1Sequence)
+        {
+            return new AlgorithmIdentifier((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public AlgorithmIdentifier(
+        DERObjectIdentifier     objectId)
+    {
+        this.objectId = objectId;
+    }
+
+    public AlgorithmIdentifier(
+        String     objectId)
+    {
+        this.objectId = new DERObjectIdentifier(objectId);
+    }
+
+    public AlgorithmIdentifier(
+        DERObjectIdentifier     objectId,
+        DEREncodable            parameters)
+    {
+        parametersDefined = true;
+        this.objectId = objectId;
+        this.parameters = parameters;
+    }
+
+    public AlgorithmIdentifier(
+        ASN1Sequence   seq)
+    {
+        if (seq.size() < 1 || seq.size() > 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + seq.size());
+        }
+        
+        objectId = DERObjectIdentifier.getInstance(seq.getObjectAt(0));
+
+        if (seq.size() == 2)
+        {
+            parametersDefined = true;
+            parameters = seq.getObjectAt(1);
+        }
+        else
+        {
+            parameters = null;
+        }
+    }
+
+    public DERObjectIdentifier getObjectId()
+    {
+        return objectId;
+    }
+
+    public DEREncodable getParameters()
+    {
+        return parameters;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *      AlgorithmIdentifier ::= SEQUENCE {
+     *                            algorithm OBJECT IDENTIFIER,
+     *                            parameters ANY DEFINED BY algorithm OPTIONAL }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(objectId);
+
+        if (parametersDefined)
+        {
+            v.add(parameters);
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AttCertIssuer.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AttCertIssuer.java
new file mode 100644
index 0000000..a66f7d7
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AttCertIssuer.java
@@ -0,0 +1,89 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Choice;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+public class AttCertIssuer
+    extends ASN1Encodable
+    implements ASN1Choice
+{
+    ASN1Encodable   obj;
+    DERObject       choiceObj;
+
+    public static AttCertIssuer getInstance(
+        Object  obj)
+    {
+        if (obj instanceof AttCertIssuer)
+        {
+            return (AttCertIssuer)obj;
+        }
+        else if (obj instanceof V2Form)
+        {
+            return new AttCertIssuer(V2Form.getInstance(obj));
+        }
+        else if (obj instanceof GeneralNames)
+        {
+            return new AttCertIssuer((GeneralNames)obj);
+        }
+        else if (obj instanceof ASN1TaggedObject)
+        {
+            return new AttCertIssuer(V2Form.getInstance((ASN1TaggedObject)obj, false));
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new AttCertIssuer(GeneralNames.getInstance(obj));
+        }
+
+        throw new IllegalArgumentException("unknown object in factory: " + obj.getClass());
+    }
+    
+    public static AttCertIssuer getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject()); // must be explictly tagged
+    }
+
+    /**
+     * Don't use this one if you are trying to be RFC compliant.
+     * 
+     * @param names our GeneralNames structure
+     */
+    public AttCertIssuer(
+        GeneralNames  names)
+    {
+        obj = names;
+        choiceObj = obj.getDERObject();
+    }
+    
+    public AttCertIssuer(
+        V2Form  v2Form)
+    {
+        obj = v2Form;
+        choiceObj = new DERTaggedObject(false, 0, obj);
+    }
+
+    public ASN1Encodable getIssuer()
+    {
+        return obj;
+    }
+    
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  AttCertIssuer ::= CHOICE {
+     *       v1Form   GeneralNames,  -- MUST NOT be used in this
+     *                               -- profile
+     *       v2Form   [0] V2Form     -- v2 only
+     *  }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        return choiceObj;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AttCertValidityPeriod.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AttCertValidityPeriod.java
new file mode 100644
index 0000000..de4e684
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AttCertValidityPeriod.java
@@ -0,0 +1,84 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERGeneralizedTime;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+public class AttCertValidityPeriod
+    extends ASN1Encodable
+{
+    DERGeneralizedTime  notBeforeTime;
+    DERGeneralizedTime  notAfterTime;
+
+    public static AttCertValidityPeriod getInstance(
+            Object  obj)
+    {
+        if (obj instanceof AttCertValidityPeriod)
+        {
+            return (AttCertValidityPeriod)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new AttCertValidityPeriod((ASN1Sequence)obj);
+        }
+        
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+    
+    public AttCertValidityPeriod(
+        ASN1Sequence    seq)
+    {
+        if (seq.size() != 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + seq.size());
+        }
+
+        notBeforeTime = DERGeneralizedTime.getInstance(seq.getObjectAt(0));
+        notAfterTime = DERGeneralizedTime.getInstance(seq.getObjectAt(1));
+    }
+
+    /**
+     * @param notBeforeTime
+     * @param notAfterTime
+     */
+    public AttCertValidityPeriod(
+        DERGeneralizedTime notBeforeTime,
+        DERGeneralizedTime notAfterTime)
+    {
+        this.notBeforeTime = notBeforeTime;
+        this.notAfterTime = notAfterTime;
+    }
+
+    public DERGeneralizedTime getNotBeforeTime()
+    {
+        return notBeforeTime;
+    }
+
+    public DERGeneralizedTime getNotAfterTime()
+    {
+        return notAfterTime;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  AttCertValidityPeriod  ::= SEQUENCE {
+     *       notBeforeTime  GeneralizedTime,
+     *       notAfterTime   GeneralizedTime
+     *  } 
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(notBeforeTime);
+        v.add(notAfterTime);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/Attribute.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/Attribute.java
new file mode 100644
index 0000000..c8cbcf7
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/Attribute.java
@@ -0,0 +1,87 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+
+public class Attribute
+    extends ASN1Encodable
+{
+    private DERObjectIdentifier attrType;
+    private ASN1Set             attrValues;
+
+    /**
+     * return an Attribute object from the given object.
+     *
+     * @param o the object we want converted.
+     * @exception IllegalArgumentException if the object cannot be converted.
+     */
+    public static Attribute getInstance(
+        Object o)
+    {
+        if (o == null || o instanceof Attribute)
+        {
+            return (Attribute)o;
+        }
+        
+        if (o instanceof ASN1Sequence)
+        {
+            return new Attribute((ASN1Sequence)o);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+    
+    public Attribute(
+        ASN1Sequence seq)
+    {
+        if (seq.size() != 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+        }
+
+        attrType = DERObjectIdentifier.getInstance(seq.getObjectAt(0));
+        attrValues = ASN1Set.getInstance(seq.getObjectAt(1));
+    }
+
+    public Attribute(
+        DERObjectIdentifier attrType,
+        ASN1Set             attrValues)
+    {
+        this.attrType = attrType;
+        this.attrValues = attrValues;
+    }
+
+    public DERObjectIdentifier getAttrType()
+    {
+        return attrType;
+    }
+    
+    public ASN1Set getAttrValues()
+    {
+        return attrValues;
+    }
+
+    /** 
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * Attribute ::= SEQUENCE {
+     *     attrType OBJECT IDENTIFIER,
+     *     attrValues SET OF AttributeValue
+     * }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(attrType);
+        v.add(attrValues);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java
new file mode 100644
index 0000000..6dcb7c6
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java
@@ -0,0 +1,94 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+public class AttributeCertificate
+    extends ASN1Encodable
+{
+    AttributeCertificateInfo    acinfo;
+    AlgorithmIdentifier         signatureAlgorithm;
+    DERBitString                signatureValue;
+
+    /**
+     * @param obj
+     * @return an AttributeCertificate object
+     */
+    public static AttributeCertificate getInstance(Object obj)
+    {
+        if (obj instanceof AttributeCertificate)
+        {
+            return (AttributeCertificate)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new AttributeCertificate((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+    
+    public AttributeCertificate(
+        AttributeCertificateInfo    acinfo,
+        AlgorithmIdentifier         signatureAlgorithm,
+        DERBitString                signatureValue)
+    {
+        this.acinfo = acinfo;
+        this.signatureAlgorithm = signatureAlgorithm;
+        this.signatureValue = signatureValue;
+    }
+    
+    public AttributeCertificate(
+        ASN1Sequence    seq)
+    {
+        if (seq.size() != 3)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + seq.size());
+        }
+
+        this.acinfo = AttributeCertificateInfo.getInstance(seq.getObjectAt(0));
+        this.signatureAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
+        this.signatureValue = DERBitString.getInstance(seq.getObjectAt(2));
+    }
+    
+    public AttributeCertificateInfo getAcinfo()
+    {
+        return acinfo;
+    }
+
+    public AlgorithmIdentifier getSignatureAlgorithm()
+    {
+        return signatureAlgorithm;
+    }
+
+    public DERBitString getSignatureValue()
+    {
+        return signatureValue;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  AttributeCertificate ::= SEQUENCE {
+     *       acinfo               AttributeCertificateInfo,
+     *       signatureAlgorithm   AlgorithmIdentifier,
+     *       signatureValue       BIT STRING
+     *  }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(acinfo);
+        v.add(signatureAlgorithm);
+        v.add(signatureValue);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java
new file mode 100644
index 0000000..74770f5
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java
@@ -0,0 +1,165 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+public class AttributeCertificateInfo
+    extends ASN1Encodable
+{
+    private DERInteger              version;
+    private Holder                  holder;
+    private AttCertIssuer           issuer;
+    private AlgorithmIdentifier     signature;
+    private DERInteger              serialNumber;
+    private AttCertValidityPeriod   attrCertValidityPeriod;
+    private ASN1Sequence            attributes;
+    private DERBitString            issuerUniqueID;
+    private X509Extensions          extensions;
+
+    public static AttributeCertificateInfo getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static AttributeCertificateInfo getInstance(
+        Object  obj)
+    {
+        if (obj instanceof AttributeCertificateInfo)
+        {
+            return (AttributeCertificateInfo)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new AttributeCertificateInfo((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public AttributeCertificateInfo(
+        ASN1Sequence   seq)
+    {
+        if (seq.size() < 7 || seq.size() > 9)
+        {
+            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+        }
+
+        this.version = DERInteger.getInstance(seq.getObjectAt(0));
+        this.holder = Holder.getInstance(seq.getObjectAt(1));
+        this.issuer = AttCertIssuer.getInstance(seq.getObjectAt(2));
+        this.signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(3));
+        this.serialNumber = DERInteger.getInstance(seq.getObjectAt(4));
+        this.attrCertValidityPeriod = AttCertValidityPeriod.getInstance(seq.getObjectAt(5));
+        this.attributes = ASN1Sequence.getInstance(seq.getObjectAt(6));
+        
+        for (int i = 7; i < seq.size(); i++)
+        {
+            ASN1Encodable    obj = (ASN1Encodable)seq.getObjectAt(i);
+
+            if (obj instanceof DERBitString)
+            {
+                this.issuerUniqueID = DERBitString.getInstance(seq.getObjectAt(i));
+            }
+            else if (obj instanceof ASN1Sequence || obj instanceof X509Extensions)
+            {
+                this.extensions = X509Extensions.getInstance(seq.getObjectAt(i));
+            }
+        }
+    }
+    
+    public DERInteger getVersion()
+    {
+        return version;
+    }
+
+    public Holder getHolder()
+    {
+        return holder;
+    }
+
+    public AttCertIssuer getIssuer()
+    {
+        return issuer;
+    }
+
+    public AlgorithmIdentifier getSignature()
+    {
+        return signature;
+    }
+
+    public DERInteger getSerialNumber()
+    {
+        return serialNumber;
+    }
+
+    public AttCertValidityPeriod getAttrCertValidityPeriod()
+    {
+        return attrCertValidityPeriod;
+    }
+
+    public ASN1Sequence getAttributes()
+    {
+        return attributes;
+    }
+
+    public DERBitString getIssuerUniqueID()
+    {
+        return issuerUniqueID;
+    }
+
+    public X509Extensions getExtensions()
+    {
+        return extensions;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  AttributeCertificateInfo ::= SEQUENCE {
+     *       version              AttCertVersion -- version is v2,
+     *       holder               Holder,
+     *       issuer               AttCertIssuer,
+     *       signature            AlgorithmIdentifier,
+     *       serialNumber         CertificateSerialNumber,
+     *       attrCertValidityPeriod   AttCertValidityPeriod,
+     *       attributes           SEQUENCE OF Attribute,
+     *       issuerUniqueID       UniqueIdentifier OPTIONAL,
+     *       extensions           Extensions OPTIONAL
+     *  }
+     *
+     *  AttCertVersion ::= INTEGER { v2(1) }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(version);
+        v.add(holder);
+        v.add(issuer);
+        v.add(signature);
+        v.add(serialNumber);
+        v.add(attrCertValidityPeriod);
+        v.add(attributes);
+        
+        if (issuerUniqueID != null)
+        {
+            v.add(issuerUniqueID);
+        }
+        
+        if (extensions != null)
+        {
+            v.add(extensions);
+        }
+        
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AuthorityInformationAccess.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AuthorityInformationAccess.java
new file mode 100644
index 0000000..9f34436
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AuthorityInformationAccess.java
@@ -0,0 +1,95 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+
+/**
+ * The AuthorityInformationAccess object.
+ * <pre>
+ * id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
+ *
+ * AuthorityInfoAccessSyntax  ::=
+ *      SEQUENCE SIZE (1..MAX) OF AccessDescription
+ * AccessDescription  ::=  SEQUENCE {
+ *       accessMethod          OBJECT IDENTIFIER,
+ *       accessLocation        GeneralName  }
+ *
+ * id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
+ * id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }
+ * id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
+ * </pre>
+ */
+public class AuthorityInformationAccess
+    extends ASN1Encodable
+{
+    private AccessDescription[]    descriptions;
+
+    public static AuthorityInformationAccess getInstance(
+        Object  obj)
+    {
+        if (obj instanceof AuthorityInformationAccess)
+        {
+            return (AuthorityInformationAccess)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new AuthorityInformationAccess((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+ 
+    public AuthorityInformationAccess(
+        ASN1Sequence   seq)
+    {
+        descriptions = new AccessDescription[seq.size()];
+        
+        for (int i = 0; i != seq.size(); i++)
+        {
+            descriptions[i] = AccessDescription.getInstance(seq.getObjectAt(i));
+        }
+    }
+
+    /**
+     * create an AuthorityInformationAccess with the oid and location provided.
+     */
+    public AuthorityInformationAccess(
+        DERObjectIdentifier oid,
+        GeneralName location)
+    {
+        descriptions = new AccessDescription[1];
+        
+        descriptions[0] = new AccessDescription(oid, location);
+    }
+
+
+    /**
+     * 
+     * @return the access descriptions contained in this object.
+     */
+    public AccessDescription[] getAccessDescriptions()
+    {
+        return descriptions;
+    }
+    
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector vec = new ASN1EncodableVector();
+        
+        for (int i = 0; i != descriptions.length; i++)
+        {
+            vec.add(descriptions[i]);
+        }
+        
+        return new DERSequence(vec);
+    }
+
+    public String toString()
+    {
+        return ("AuthorityInformationAccess: Oid(" + this.descriptions[0].getAccessMethod().getId() + ")");
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java
new file mode 100644
index 0000000..2e5107b
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java
@@ -0,0 +1,207 @@
+package org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.*;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.SHA1Digest;
+
+/**
+ * The AuthorityKeyIdentifier object.
+ * <pre>
+ * id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 35 }
+ *
+ *   AuthorityKeyIdentifier ::= SEQUENCE {
+ *      keyIdentifier             [0] IMPLICIT KeyIdentifier           OPTIONAL,
+ *      authorityCertIssuer       [1] IMPLICIT GeneralNames            OPTIONAL,
+ *      authorityCertSerialNumber [2] IMPLICIT CertificateSerialNumber OPTIONAL  }
+ *
+ *   KeyIdentifier ::= OCTET STRING
+ * </pre>
+ *
+ */
+public class AuthorityKeyIdentifier
+    extends ASN1Encodable
+{
+    ASN1OctetString keyidentifier=null;
+    GeneralNames certissuer=null;
+    DERInteger certserno=null;
+
+    public static AuthorityKeyIdentifier getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static AuthorityKeyIdentifier getInstance(
+        Object  obj)
+    {
+        if (obj instanceof AuthorityKeyIdentifier)
+        {
+            return (AuthorityKeyIdentifier)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new AuthorityKeyIdentifier((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public AuthorityKeyIdentifier(
+        ASN1Sequence   seq)
+    {
+        Enumeration     e = seq.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            ASN1TaggedObject o = DERTaggedObject.getInstance(e.nextElement());
+
+            switch (o.getTagNo())
+            {
+            case 0:
+                this.keyidentifier = ASN1OctetString.getInstance(o, false);
+                break;
+            case 1:
+                this.certissuer = GeneralNames.getInstance(o, false);
+                break;
+            case 2:
+                this.certserno = DERInteger.getInstance(o, false);
+                break;
+            default:
+                throw new IllegalArgumentException("illegal tag");
+            }
+        }
+    }
+
+    /**
+     *
+     * Calulates the keyidentifier using a SHA1 hash over the BIT STRING
+     * from SubjectPublicKeyInfo as defined in RFC2459.
+     *
+     * Example of making a AuthorityKeyIdentifier:
+     * <pre>
+     *   SubjectPublicKeyInfo apki = new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream(
+     *       publicKey.getEncoded()).readObject());
+     *   AuthorityKeyIdentifier aki = new AuthorityKeyIdentifier(apki);
+     * </pre>
+     *
+     **/
+    public AuthorityKeyIdentifier(
+        SubjectPublicKeyInfo    spki)
+    {
+        Digest  digest = new SHA1Digest();
+        byte[]  resBuf = new byte[digest.getDigestSize()];
+
+        byte[] bytes = spki.getPublicKeyData().getBytes();
+        digest.update(bytes, 0, bytes.length);
+        digest.doFinal(resBuf, 0);
+        this.keyidentifier = new DEROctetString(resBuf);
+    }
+
+    /**
+     * create an AuthorityKeyIdentifier with the GeneralNames tag and
+     * the serial number provided as well.
+     */
+    public AuthorityKeyIdentifier(
+        SubjectPublicKeyInfo    spki,
+        GeneralNames            name,
+        BigInteger              serialNumber)
+    {
+        Digest  digest = new SHA1Digest();
+        byte[]  resBuf = new byte[digest.getDigestSize()];
+
+        byte[] bytes = spki.getPublicKeyData().getBytes();
+        digest.update(bytes, 0, bytes.length);
+        digest.doFinal(resBuf, 0);
+
+        this.keyidentifier = new DEROctetString(resBuf);
+        this.certissuer = GeneralNames.getInstance(name.toASN1Object());
+        this.certserno = new DERInteger(serialNumber);
+    }
+
+    /**
+     * create an AuthorityKeyIdentifier with the GeneralNames tag and
+     * the serial number provided.
+     */
+    public AuthorityKeyIdentifier(
+        GeneralNames            name,
+        BigInteger              serialNumber)
+    {
+        this.keyidentifier = null;
+        this.certissuer = GeneralNames.getInstance(name.toASN1Object());
+        this.certserno = new DERInteger(serialNumber);
+    }
+
+    /**
+     * create an AuthorityKeyIdentifier with a precomupted key identifier
+     * and the GeneralNames tag and the serial number provided as well.
+     */
+    public AuthorityKeyIdentifier(
+        byte[]                  keyIdentifier,
+        GeneralNames            name,
+        BigInteger              serialNumber)
+    {
+        this.keyidentifier = new DEROctetString(keyIdentifier);
+        this.certissuer = GeneralNames.getInstance(name.toASN1Object());
+        this.certserno = new DERInteger(serialNumber);
+    }
+    
+    public byte[] getKeyIdentifier()
+    {
+        if (keyidentifier != null)
+        {
+            return keyidentifier.getOctets();
+        }
+
+        return null;
+    }
+
+    public GeneralNames getAuthorityCertIssuer()
+    {
+        return certissuer;
+    }
+    
+    public BigInteger getAuthorityCertSerialNumber()
+    {
+        if (certserno != null)
+        {
+            return certserno.getValue();
+        }
+        
+        return null;
+    }
+    
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        if (keyidentifier != null)
+        {
+            v.add(new DERTaggedObject(false, 0, keyidentifier));
+        }
+
+        if (certissuer != null)
+        {
+            v.add(new DERTaggedObject(false, 1, certissuer));
+        }
+
+        if (certserno != null)
+        {
+            v.add(new DERTaggedObject(false, 2, certserno));
+        }
+
+
+        return new DERSequence(v);
+    }
+
+    public String toString()
+    {
+        return ("AuthorityKeyIdentifier: KeyID(" + this.keyidentifier.getOctets() + ")");
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java
new file mode 100644
index 0000000..c97b6cd
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java
@@ -0,0 +1,168 @@
+package org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERBoolean;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+public class BasicConstraints
+    extends ASN1Encodable
+{
+    // BEGIN android-changed
+    DERBoolean  cA = DERBoolean.FALSE;
+    // END android-changed
+    DERInteger  pathLenConstraint = null;
+
+    public static BasicConstraints getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static BasicConstraints getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof BasicConstraints)
+        {
+            return (BasicConstraints)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new BasicConstraints((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+    
+    public BasicConstraints(
+        ASN1Sequence   seq)
+    {
+        if (seq.size() == 0)
+        {
+            this.cA = null;
+            this.pathLenConstraint = null;
+        }
+        else
+        {
+            this.cA = DERBoolean.getInstance(seq.getObjectAt(0));
+            if (seq.size() > 1)
+            {
+                this.pathLenConstraint = DERInteger.getInstance(seq.getObjectAt(1));
+            }
+        }
+    }
+
+    /**
+     * @deprecated use one of the other two unambigous constructors.
+     * @param cA
+     * @param pathLenConstraint
+     */
+    public BasicConstraints(
+        boolean cA,
+        int     pathLenConstraint)
+    {
+        if (cA)
+        {
+            // BEGIN android-changed
+            this.cA = DERBoolean.getInstance(cA);
+            // END android-changed
+            this.pathLenConstraint = new DERInteger(pathLenConstraint);
+        }
+        else
+        {
+            this.cA = null;
+            this.pathLenConstraint = null;
+        }
+    }
+
+    public BasicConstraints(
+        boolean cA)
+    {
+        if (cA)
+        {
+            // BEGIN android-changed
+            this.cA = DERBoolean.TRUE;
+            // END android-changed
+        }
+        else
+        {
+            this.cA = null;
+        }
+        this.pathLenConstraint = null;
+    }
+
+    /**
+     * create a cA=true object for the given path length constraint.
+     * 
+     * @param pathLenConstraint
+     */
+    public BasicConstraints(
+        int     pathLenConstraint)
+    {
+        // BEGIN android-changed
+        this.cA = DERBoolean.TRUE;
+        // END android-changed
+        this.pathLenConstraint = new DERInteger(pathLenConstraint);
+    }
+
+    public boolean isCA()
+    {
+        return (cA != null) && cA.isTrue();
+    }
+
+    public BigInteger getPathLenConstraint()
+    {
+        if (pathLenConstraint != null)
+        {
+            return pathLenConstraint.getValue();
+        }
+
+        return null;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * BasicConstraints := SEQUENCE {
+     *    cA                  BOOLEAN DEFAULT FALSE,
+     *    pathLenConstraint   INTEGER (0..MAX) OPTIONAL
+     * }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        if (cA != null)
+        {
+            v.add(cA);
+    
+            if (pathLenConstraint != null)
+            {
+                v.add(pathLenConstraint);
+            }
+        }
+
+        return new DERSequence(v);
+    }
+
+    public String toString()
+    {
+        if (pathLenConstraint == null)
+        {
+            if (cA == null)
+            {
+                return "BasicConstraints: isCa(false)";
+            }
+            return "BasicConstraints: isCa(" + this.isCA() + ")";
+        }
+        return "BasicConstraints: isCa(" + this.isCA() + "), pathLenConstraint = " + pathLenConstraint.getValue();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java
new file mode 100644
index 0000000..ed8ab58
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java
@@ -0,0 +1,83 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+public class CRLDistPoint
+    extends ASN1Encodable
+{
+    ASN1Sequence  seq = null;
+
+    public static CRLDistPoint getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static CRLDistPoint getInstance(
+        Object  obj)
+    {
+        if (obj instanceof CRLDistPoint)
+        {
+            return (CRLDistPoint)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new CRLDistPoint((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public CRLDistPoint(
+        ASN1Sequence seq)
+    {
+        this.seq = seq;
+    }
+    
+    public CRLDistPoint(
+        DistributionPoint[] points)
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        for (int i = 0; i != points.length; i++)
+        {
+            v.add(points[i]);
+        }
+
+        seq = new DERSequence(v);
+    }
+
+    /**
+     * Return the distribution points making up the sequence.
+     * 
+     * @return DistributionPoint[]
+     */
+    public DistributionPoint[] getDistributionPoints()
+    {
+        DistributionPoint[]    dp = new DistributionPoint[seq.size()];
+        
+        for (int i = 0; i != seq.size(); i++)
+        {
+            dp[i] = DistributionPoint.getInstance(seq.getObjectAt(i));
+        }
+        
+        return dp;
+    }
+    
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * CRLDistPoint ::= SEQUENCE SIZE {1..MAX} OF DistributionPoint
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        return seq;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/CRLNumber.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/CRLNumber.java
new file mode 100644
index 0000000..e488086
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/CRLNumber.java
@@ -0,0 +1,27 @@
+package org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.DERInteger;
+
+/**
+ * The CRLNumber object.
+ * <pre>
+ * CRLNumber::= INTEGER(0..MAX)
+ * </pre>
+ */
+public class CRLNumber
+    extends DERInteger
+{
+
+    public CRLNumber(
+        BigInteger number)
+    {
+        super(number);
+    }
+
+    public BigInteger getCRLNumber()
+    {
+        return getPositiveValue();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/CRLReason.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/CRLReason.java
new file mode 100644
index 0000000..265c662
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/CRLReason.java
@@ -0,0 +1,88 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.DEREnumerated;
+
+/**
+ * The CRLReason enumeration.
+ * <pre>
+ * CRLReason ::= ENUMERATED {
+ *  unspecified             (0),
+ *  keyCompromise           (1),
+ *  cACompromise            (2),
+ *  affiliationChanged      (3),
+ *  superseded              (4),
+ *  cessationOfOperation    (5),
+ *  certificateHold         (6),
+ *  removeFromCRL           (8),
+ *  privilegeWithdrawn      (9),
+ *  aACompromise           (10)
+ * }
+ * </pre>
+ */
+public class CRLReason
+    extends DEREnumerated
+{
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int UNSPECIFIED = 0;
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int KEY_COMPROMISE = 1;
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int CA_COMPROMISE = 2;
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int AFFILIATION_CHANGED = 3;
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int SUPERSEDED = 4;
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int CESSATION_OF_OPERATION  = 5;
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int CERTIFICATE_HOLD = 6;
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int REMOVE_FROM_CRL = 8;
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int PRIVILEGE_WITHDRAWN = 9;
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int AA_COMPROMISE = 10;
+
+    public static final int unspecified = 0;
+    public static final int keyCompromise = 1;
+    public static final int cACompromise = 2;
+    public static final int affiliationChanged = 3;
+    public static final int superseded = 4;
+    public static final int cessationOfOperation  = 5;
+    public static final int certificateHold = 6;
+    public static final int removeFromCRL = 8;
+    public static final int privilegeWithdrawn = 9;
+    public static final int aACompromise = 10;
+    
+    public CRLReason(
+        int reason)
+    {
+        super(reason);
+    }
+
+    public CRLReason(
+        DEREnumerated reason)
+    {
+        super(reason.getValue().intValue());
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/CertPolicyId.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/CertPolicyId.java
new file mode 100644
index 0000000..3e85dbd
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/CertPolicyId.java
@@ -0,0 +1,20 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+
+/**
+ * CertPolicyId, used in the CertificatePolicies and PolicyMappings
+ * X509V3 Extensions.
+ *
+ * <pre>
+ *     CertPolicyId ::= OBJECT IDENTIFIER
+ * </pre>
+ */
+public class CertPolicyId extends DERObjectIdentifier 
+{
+   public CertPolicyId (String id) 
+   {
+     super(id);
+   }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java
new file mode 100644
index 0000000..c7f890b
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java
@@ -0,0 +1,119 @@
+
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+/**
+ * PKIX RFC-2459
+ *
+ * The X.509 v2 CRL syntax is as follows.  For signature calculation,
+ * the data that is to be signed is ASN.1 DER encoded.
+ *
+ * <pre>
+ * CertificateList  ::=  SEQUENCE  {
+ *      tbsCertList          TBSCertList,
+ *      signatureAlgorithm   AlgorithmIdentifier,
+ *      signatureValue       BIT STRING  }
+ * </pre>
+ */
+public class CertificateList
+    extends ASN1Encodable
+{
+    TBSCertList            tbsCertList;
+    AlgorithmIdentifier    sigAlgId;
+    DERBitString           sig;
+
+    public static CertificateList getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static CertificateList getInstance(
+        Object  obj)
+    {
+        if (obj instanceof CertificateList)
+        {
+            return (CertificateList)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new CertificateList((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public CertificateList(
+        ASN1Sequence seq)
+    {
+        if (seq.size() == 3)
+        {
+            tbsCertList = TBSCertList.getInstance(seq.getObjectAt(0));
+            sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
+            sig = DERBitString.getInstance(seq.getObjectAt(2));
+        }
+        else
+        {
+            throw new IllegalArgumentException("sequence wrong size for CertificateList");
+        }
+    }
+
+    public TBSCertList getTBSCertList()
+    {
+        return tbsCertList;
+    }
+
+    public TBSCertList.CRLEntry[] getRevokedCertificates()
+    {
+        return tbsCertList.getRevokedCertificates();
+    }
+
+    public AlgorithmIdentifier getSignatureAlgorithm()
+    {
+        return sigAlgId;
+    }
+
+    public DERBitString getSignature()
+    {
+        return sig;
+    }
+
+    public int getVersion()
+    {
+        return tbsCertList.getVersion();
+    }
+
+    public X509Name getIssuer()
+    {
+        return tbsCertList.getIssuer();
+    }
+
+    public Time getThisUpdate()
+    {
+        return tbsCertList.getThisUpdate();
+    }
+
+    public Time getNextUpdate()
+    {
+        return tbsCertList.getNextUpdate();
+    }
+
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(tbsCertList);
+        v.add(sigAlgId);
+        v.add(sig);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/CertificatePolicies.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/CertificatePolicies.java
new file mode 100644
index 0000000..b59e08e
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/CertificatePolicies.java
@@ -0,0 +1,147 @@
+package org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+
+public class CertificatePolicies
+    extends ASN1Encodable
+{
+    static final DERObjectIdentifier anyPolicy = new DERObjectIdentifier("2.5.29.32.0");
+
+    Vector policies = new Vector();
+
+/**
+ * @deprecated use an ASN1Sequence of PolicyInformation
+ */
+    public static CertificatePolicies getInstance(
+        ASN1TaggedObject obj,
+        boolean explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+/**
+ * @deprecated use an ASN1Sequence of PolicyInformation
+ */
+    public static CertificatePolicies getInstance(
+        Object  obj)
+    {
+        if (obj instanceof CertificatePolicies)
+        {
+            return (CertificatePolicies)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new CertificatePolicies((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+/**
+ * @deprecated use an ASN1Sequence of PolicyInformation
+ */
+    public CertificatePolicies(
+        ASN1Sequence   seq)
+    {
+        Enumeration e = seq.getObjects();
+        while (e.hasMoreElements())
+        {
+            ASN1Sequence s = ASN1Sequence.getInstance(e.nextElement());
+            policies.addElement(s.getObjectAt(0));
+        }
+        // For now we just don't handle PolicyQualifiers
+    }
+
+    /**
+     * create a certificate policy with the given OID.
+     * @deprecated use an ASN1Sequence of PolicyInformation
+     */
+    public CertificatePolicies(
+        DERObjectIdentifier p)
+    {
+        policies.addElement(p);
+    }
+
+    /**
+     * create a certificate policy with the policy given by the OID represented
+     * by the string p.
+     * @deprecated use an ASN1Sequence of PolicyInformation
+     */
+    public CertificatePolicies(
+        String p)
+    {
+        this(new DERObjectIdentifier(p));
+    }
+
+    public void addPolicy(
+        String p)
+    {
+        policies.addElement(new DERObjectIdentifier(p));
+    }
+
+    public String getPolicy(int nr)
+    {
+        if (policies.size() > nr)
+        {
+            return ((DERObjectIdentifier)policies.elementAt(nr)).getId();
+        }
+        
+        return null;
+    }
+
+    /**
+     * <pre>
+     * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
+     *
+     * PolicyInformation ::= SEQUENCE {
+     *   policyIdentifier   CertPolicyId,
+     *   policyQualifiers   SEQUENCE SIZE (1..MAX) OF
+     *                           PolicyQualifierInfo OPTIONAL }
+     *
+     * CertPolicyId ::= OBJECT IDENTIFIER
+     *
+     * PolicyQualifierInfo ::= SEQUENCE {
+     *   policyQualifierId  PolicyQualifierId,
+     *   qualifier          ANY DEFINED BY policyQualifierId }
+     *
+     * PolicyQualifierId ::=
+     *   OBJECT IDENTIFIER (id-qt-cps | id-qt-unotice)
+     * </pre>
+     * @deprecated use an ASN1Sequence of PolicyInformation
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        // We only do policyIdentifier yet...
+        for (int i=0;i<policies.size();i++)
+        {
+            v.add(new DERSequence((DERObjectIdentifier)policies.elementAt(i)));
+        }
+
+        return new DERSequence(v);
+    }
+
+    public String toString()
+    {
+        String p = null;
+        for (int i=0;i<policies.size();i++)
+        {
+            if (p != null)
+            {
+                p += ", ";
+            }
+            p += ((DERObjectIdentifier)policies.elementAt(i)).getId();
+        }
+        return "CertificatePolicies: "+p;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/DSAParameter.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/DSAParameter.java
new file mode 100644
index 0000000..50822d6
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/DSAParameter.java
@@ -0,0 +1,92 @@
+package org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+public class DSAParameter
+    extends ASN1Encodable
+{
+    DERInteger      p, q, g;
+
+    public static DSAParameter getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static DSAParameter getInstance(
+        Object obj)
+    {
+        if(obj == null || obj instanceof DSAParameter) 
+        {
+            return (DSAParameter)obj;
+        }
+        
+        if(obj instanceof ASN1Sequence) 
+        {
+            return new DSAParameter((ASN1Sequence)obj);
+        }
+        
+        throw new IllegalArgumentException("Invalid DSAParameter: " + obj.getClass().getName());
+    }
+
+    public DSAParameter(
+        BigInteger  p,
+        BigInteger  q,
+        BigInteger  g)
+    {
+        this.p = new DERInteger(p);
+        this.q = new DERInteger(q);
+        this.g = new DERInteger(g);
+    }
+
+    public DSAParameter(
+        ASN1Sequence  seq)
+    {
+        if (seq.size() != 3)
+        {
+            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+        }
+        
+        Enumeration     e = seq.getObjects();
+
+        p = DERInteger.getInstance(e.nextElement());
+        q = DERInteger.getInstance(e.nextElement());
+        g = DERInteger.getInstance(e.nextElement());
+    }
+
+    public BigInteger getP()
+    {
+        return p.getPositiveValue();
+    }
+
+    public BigInteger getQ()
+    {
+        return q.getPositiveValue();
+    }
+
+    public BigInteger getG()
+    {
+        return g.getPositiveValue();
+    }
+
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(p);
+        v.add(q);
+        v.add(g);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/DigestInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/DigestInfo.java
new file mode 100644
index 0000000..882e71e
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/DigestInfo.java
@@ -0,0 +1,86 @@
+package org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+
+/**
+ * The DigestInfo object.
+ * <pre>
+ * DigestInfo::=SEQUENCE{
+ *          digestAlgorithm  AlgorithmIdentifier,
+ *          digest OCTET STRING }
+ * </pre>
+ */
+public class DigestInfo
+    extends ASN1Encodable
+{
+    private byte[]                  digest;
+    private AlgorithmIdentifier     algId;
+
+    public static DigestInfo getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static DigestInfo getInstance(
+        Object  obj)
+    {
+        if (obj instanceof DigestInfo)
+        {
+            return (DigestInfo)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new DigestInfo((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public DigestInfo(
+        AlgorithmIdentifier  algId,
+        byte[]               digest)
+    {
+        this.digest = digest;
+        this.algId = algId;
+    }
+
+    public DigestInfo(
+        ASN1Sequence  obj)
+    {
+        Enumeration             e = obj.getObjects();
+
+        algId = AlgorithmIdentifier.getInstance(e.nextElement());
+        digest = ASN1OctetString.getInstance(e.nextElement()).getOctets();
+    }
+
+    public AlgorithmIdentifier getAlgorithmId()
+    {
+        return algId;
+    }
+
+    public byte[] getDigest()
+    {
+        return digest;
+    }
+
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(algId);
+        v.add(new DEROctetString(digest));
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/DisplayText.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/DisplayText.java
new file mode 100644
index 0000000..90b025e
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/DisplayText.java
@@ -0,0 +1,165 @@
+
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Choice;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERBMPString;
+import org.bouncycastle.asn1.DERIA5String;
+import org.bouncycastle.asn1.DERUTF8String;
+import org.bouncycastle.asn1.DERVisibleString;
+import org.bouncycastle.asn1.DERString;
+
+/**
+ * <code>DisplayText</code> class, used in
+ * <code>CertificatePolicies</code> X509 V3 extensions (in policy qualifiers).
+ *
+ * <p>It stores a string in a chosen encoding. 
+ * <pre>
+ * DisplayText ::= CHOICE {
+ *      ia5String        IA5String      (SIZE (1..200)),
+ *      visibleString    VisibleString  (SIZE (1..200)),
+ *      bmpString        BMPString      (SIZE (1..200)),
+ *      utf8String       UTF8String     (SIZE (1..200)) }
+ * </pre>
+ * @see PolicyQualifierInfo
+ * @see PolicyInformation
+ */
+public class DisplayText 
+    extends ASN1Encodable
+    implements ASN1Choice
+{
+   /**
+    * Constant corresponding to ia5String encoding. 
+    *
+    */
+   public static final int CONTENT_TYPE_IA5STRING = 0;
+   /**
+    * Constant corresponding to bmpString encoding. 
+    *
+    */
+   public static final int CONTENT_TYPE_BMPSTRING = 1;
+   /**
+    * Constant corresponding to utf8String encoding. 
+    *
+    */
+   public static final int CONTENT_TYPE_UTF8STRING = 2;
+   /**
+    * Constant corresponding to visibleString encoding. 
+    *
+    */
+   public static final int CONTENT_TYPE_VISIBLESTRING = 3;
+
+   /**
+    * Describe constant <code>DISPLAY_TEXT_MAXIMUM_SIZE</code> here.
+    *
+    */
+   public static final int DISPLAY_TEXT_MAXIMUM_SIZE = 200;
+   
+   int contentType;
+   DERString contents;
+   
+   /**
+    * Creates a new <code>DisplayText</code> instance.
+    *
+    * @param type the desired encoding type for the text. 
+    * @param text the text to store. Strings longer than 200
+    * characters are truncated. 
+    */
+   public DisplayText (int type, String text) 
+   {
+      if (text.length() > DISPLAY_TEXT_MAXIMUM_SIZE)
+      {
+         // RFC3280 limits these strings to 200 chars
+         // truncate the string
+         text = text.substring (0, DISPLAY_TEXT_MAXIMUM_SIZE);
+      }
+     
+      contentType = type;
+      switch (type)
+      {
+         case CONTENT_TYPE_IA5STRING:
+            contents = (DERString)new DERIA5String (text);
+            break;
+         case CONTENT_TYPE_UTF8STRING:
+            contents = (DERString)new DERUTF8String(text);
+            break;
+         case CONTENT_TYPE_VISIBLESTRING:
+            contents = (DERString)new DERVisibleString(text);
+            break;
+         case CONTENT_TYPE_BMPSTRING:
+            contents = (DERString)new DERBMPString(text);
+            break;
+         default:
+            contents = (DERString)new DERUTF8String(text);
+            break;
+      }
+   }
+   
+   /**
+    * Creates a new <code>DisplayText</code> instance.
+    *
+    * @param text the text to encapsulate. Strings longer than 200
+    * characters are truncated. 
+    */
+   public DisplayText (String text) 
+   {
+      // by default use UTF8String
+      if (text.length() > DISPLAY_TEXT_MAXIMUM_SIZE)
+      {
+         text = text.substring(0, DISPLAY_TEXT_MAXIMUM_SIZE);
+      }
+      
+      contentType = CONTENT_TYPE_UTF8STRING;
+      contents = new DERUTF8String(text);
+   }
+
+   /**
+    * Creates a new <code>DisplayText</code> instance.
+    * <p>Useful when reading back a <code>DisplayText</code> class
+    * from it's ASN1Encodable/DEREncodable form. 
+    *
+    * @param de a <code>DEREncodable</code> instance. 
+    */
+   public DisplayText(DERString de)
+   {
+      contents = de;
+   }
+
+   public static DisplayText getInstance(Object de) 
+   {
+      if (de instanceof DERString)
+      {
+          return new DisplayText((DERString)de);
+      }
+      else if (de instanceof DisplayText)
+      {
+          return (DisplayText)de;
+      }
+
+      throw new IllegalArgumentException("illegal object in getInstance");
+   }
+
+   public static DisplayText getInstance(
+       ASN1TaggedObject obj,
+       boolean          explicit)
+   {
+       return getInstance(obj.getObject()); // must be explicitly tagged
+   }
+   
+   public DERObject toASN1Object() 
+   {
+      return (DERObject)contents;
+   }
+
+   /**
+    * Returns the stored <code>String</code> object. 
+    *
+    * @return the stored text as a <code>String</code>. 
+    */
+   public String getString() 
+   {
+      return contents.getString();
+   }   
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java
new file mode 100644
index 0000000..ea5aa0b
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java
@@ -0,0 +1,121 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * The DistributionPoint object.
+ * <pre>
+ * DistributionPoint ::= SEQUENCE {
+ *      distributionPoint [0] DistributionPointName OPTIONAL,
+ *      reasons           [1] ReasonFlags OPTIONAL,
+ *      cRLIssuer         [2] GeneralNames OPTIONAL
+ * }
+ * </pre>
+ */
+public class DistributionPoint
+    extends ASN1Encodable
+{
+    DistributionPointName       distributionPoint;
+    ReasonFlags                 reasons;
+    GeneralNames                cRLIssuer;
+
+    public static DistributionPoint getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static DistributionPoint getInstance(
+        Object obj)
+    {
+        if(obj == null || obj instanceof DistributionPoint) 
+        {
+            return (DistributionPoint)obj;
+        }
+        
+        if(obj instanceof ASN1Sequence) 
+        {
+            return new DistributionPoint((ASN1Sequence)obj);
+        }
+        
+        throw new IllegalArgumentException("Invalid DistributionPoint: " + obj.getClass().getName());
+    }
+
+    public DistributionPoint(
+        ASN1Sequence seq)
+    {
+        for (int i = 0; i != seq.size(); i++)
+        {
+            ASN1TaggedObject    t = ASN1TaggedObject.getInstance(seq.getObjectAt(i));
+            switch (t.getTagNo())
+            {
+            case 0:
+                distributionPoint = DistributionPointName.getInstance(t, true);
+                break;
+            case 1:
+                reasons = new ReasonFlags(DERBitString.getInstance(t, false));
+                break;
+            case 2:
+                cRLIssuer = GeneralNames.getInstance(t, false);
+            }
+        }
+    }
+    
+    public DistributionPoint(
+        DistributionPointName distributionPoint,
+        ReasonFlags                 reasons,
+        GeneralNames            cRLIssuer)
+    {
+        this.distributionPoint = distributionPoint;
+        this.reasons = reasons;
+        this.cRLIssuer = cRLIssuer;
+    }
+    
+    public DistributionPointName getDistributionPoint()
+    {
+        return distributionPoint;
+    }
+
+    public ReasonFlags getReasons()
+    {
+        return reasons;
+    }
+    
+    public GeneralNames getCRLIssuer()
+    {
+        return cRLIssuer;
+    }
+    
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+        
+        if (distributionPoint != null)
+        {
+            //
+            // as this is a CHOICE it must be explicitly tagged
+            //
+            v.add(new DERTaggedObject(0, distributionPoint));
+        }
+
+        if (reasons != null)
+        {
+            v.add(new DERTaggedObject(false, 1, reasons));
+        }
+
+        if (cRLIssuer != null)
+        {
+            v.add(new DERTaggedObject(false, 2, cRLIssuer));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java
new file mode 100644
index 0000000..91ef110
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java
@@ -0,0 +1,110 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Choice;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * The DistributionPointName object.
+ * <pre>
+ * DistributionPointName ::= CHOICE {
+ *     fullName                 [0] GeneralNames,
+ *     nameRelativeToCRLIssuer  [1] RelativeDistinguishedName
+ * }
+ * </pre>
+ */
+public class DistributionPointName
+    extends ASN1Encodable
+    implements ASN1Choice
+{
+    DEREncodable        name;
+    int                 type;
+
+    public static final int FULL_NAME = 0;
+    public static final int NAME_RELATIVE_TO_CRL_ISSUER = 1;
+
+    public static DistributionPointName getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1TaggedObject.getInstance(obj, true));
+    }
+
+    public static DistributionPointName getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof DistributionPointName)
+        {
+            return (DistributionPointName)obj;
+        }
+        else if (obj instanceof ASN1TaggedObject)
+        {
+            return new DistributionPointName((ASN1TaggedObject)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    /*
+     * @deprecated use ASN1Encodable
+     */
+    public DistributionPointName(
+        int             type,
+        DEREncodable    name)
+    {
+        this.type = type;
+        this.name = name;
+    }
+
+    public DistributionPointName(
+        int             type,
+        ASN1Encodable   name)
+    {
+        this.type = type;
+        this.name = name;
+    }
+    
+    /**
+     * Return the tag number applying to the underlying choice.
+     * 
+     * @return the tag number for this point name.
+     */
+    public int getType()
+    {
+        return this.type;
+    }
+    
+    /**
+     * Return the tagged object inside the distribution point name.
+     * 
+     * @return the underlying choice item.
+     */
+    public ASN1Encodable getName()
+    {
+        return (ASN1Encodable)name;
+    }
+    
+    public DistributionPointName(
+        ASN1TaggedObject    obj)
+    {
+        this.type = obj.getTagNo();
+        
+        if (type == 0)
+        {
+            this.name = GeneralNames.getInstance(obj, false);
+        }
+        else
+        {
+            this.name = ASN1Set.getInstance(obj, false);
+        }
+    }
+    
+    public DERObject toASN1Object()
+    {
+        return new DERTaggedObject(false, type, name);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java
new file mode 100644
index 0000000..a84b97f
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java
@@ -0,0 +1,104 @@
+package org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+/**
+ * The extendedKeyUsage object.
+ * <pre>
+ *      extendedKeyUsage ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
+ * </pre>
+ */
+public class ExtendedKeyUsage
+    extends ASN1Encodable
+{
+    Hashtable     usageTable = new Hashtable();
+    ASN1Sequence  seq;
+
+    public static ExtendedKeyUsage getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static ExtendedKeyUsage getInstance(
+        Object obj)
+    {
+        if(obj == null || obj instanceof ExtendedKeyUsage) 
+        {
+            return (ExtendedKeyUsage)obj;
+        }
+        
+        if(obj instanceof ASN1Sequence) 
+        {
+            return new ExtendedKeyUsage((ASN1Sequence)obj);
+        }
+        
+        throw new IllegalArgumentException("Invalid ExtendedKeyUsage: " + obj.getClass().getName());
+    }
+
+    public ExtendedKeyUsage(
+        KeyPurposeId  usage)
+    {
+        this.seq = new DERSequence(usage);
+
+        this.usageTable.put(usage, usage);
+    }
+    
+    public ExtendedKeyUsage(
+        ASN1Sequence  seq)
+    {
+        this.seq = seq;
+
+        Enumeration e = seq.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            Object  o = e.nextElement();
+
+            this.usageTable.put(o, o);
+        }
+    }
+
+    public ExtendedKeyUsage(
+        Vector  usages)
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+        Enumeration         e = usages.elements();
+
+        while (e.hasMoreElements())
+        {
+            DERObject  o = (DERObject)e.nextElement();
+
+            v.add(o);
+            this.usageTable.put(o, o);
+        }
+
+        this.seq = new DERSequence(v);
+    }
+
+    public boolean hasKeyPurposeId(
+        KeyPurposeId keyPurposeId)
+    {
+        return (usageTable.get(keyPurposeId) != null);
+    }
+
+    public int size()
+    {
+        return usageTable.size();
+    }
+    
+    public DERObject toASN1Object()
+    {
+        return seq;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/GeneralName.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/GeneralName.java
new file mode 100644
index 0000000..e015cee
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/GeneralName.java
@@ -0,0 +1,201 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Choice;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERIA5String;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * The GeneralName object.
+ * <pre>
+ * GeneralName ::= CHOICE {
+ *      otherName                       [0]     OtherName,
+ *      rfc822Name                      [1]     IA5String,
+ *      dNSName                         [2]     IA5String,
+ *      x400Address                     [3]     ORAddress,
+ *      directoryName                   [4]     Name,
+ *      ediPartyName                    [5]     EDIPartyName,
+ *      uniformResourceIdentifier       [6]     IA5String,
+ *      iPAddress                       [7]     OCTET STRING,
+ *      registeredID                    [8]     OBJECT IDENTIFIER}
+ *
+ * OtherName ::= SEQUENCE {
+ *      type-id    OBJECT IDENTIFIER,
+ *      value      [0] EXPLICIT ANY DEFINED BY type-id }
+ *
+ * EDIPartyName ::= SEQUENCE {
+ *      nameAssigner            [0]     DirectoryString OPTIONAL,
+ *      partyName               [1]     DirectoryString }
+ * 
+ * Name ::= CHOICE { RDNSequence }
+ * </pre>
+ */
+public class GeneralName
+    extends ASN1Encodable
+    implements ASN1Choice
+{
+    public static final int otherName                     = 0;
+    public static final int rfc822Name                    = 1;
+    public static final int dNSName                       = 2;
+    public static final int x400Address                   = 3;
+    public static final int directoryName                 = 4;
+    public static final int ediPartyName                  = 5;
+    public static final int uniformResourceIdentifier     = 6;
+    public static final int iPAddress                     = 7;
+    public static final int registeredID                  = 8;
+
+    DEREncodable      obj;
+    int               tag;
+   
+    public GeneralName(
+        X509Name  dirName)
+    {
+        this.obj = dirName;
+        this.tag = 4;
+    }
+
+    /**
+     * @deprecated this constructor seems the wrong way round! Use GeneralName(tag, name).
+     */
+    public GeneralName(
+        DERObject name, int tag)
+    {
+        this.obj = name;
+        this.tag = tag;
+    }
+
+    /**
+     * When the subjectAltName extension contains an Internet mail address,
+     * the address MUST be included as an rfc822Name. The format of an
+     * rfc822Name is an "addr-spec" as defined in RFC 822 [RFC 822].
+     *
+     * When the subjectAltName extension contains a domain name service
+     * label, the domain name MUST be stored in the dNSName (an IA5String).
+     * The name MUST be in the "preferred name syntax," as specified by RFC
+     * 1034 [RFC 1034].
+     *
+     * When the subjectAltName extension contains a URI, the name MUST be
+     * stored in the uniformResourceIdentifier (an IA5String). The name MUST
+     * be a non-relative URL, and MUST follow the URL syntax and encoding
+     * rules specified in [RFC 1738].  The name must include both a scheme
+     * (e.g., "http" or "ftp") and a scheme-specific-part.  The scheme-
+     * specific-part must include a fully qualified domain name or IP
+     * address as the host.
+     *
+     * When the subjectAltName extension contains a iPAddress, the address
+     * MUST be stored in the octet string in "network byte order," as
+     * specified in RFC 791 [RFC 791]. The least significant bit (LSB) of
+     * each octet is the LSB of the corresponding byte in the network
+     * address. For IP Version 4, as specified in RFC 791, the octet string
+     * MUST contain exactly four octets.  For IP Version 6, as specified in
+     * RFC 1883, the octet string MUST contain exactly sixteen octets [RFC
+     * 1883].
+     */
+    public GeneralName(
+        int           tag,
+        ASN1Encodable name)
+    {
+        this.obj = name;
+        this.tag = tag;
+    }
+    
+    /**
+     * Create a General name for the given tag from the passed in String.
+     * 
+     * @param tag tag number
+     * @param name string representation of name
+     */
+    public GeneralName(
+        int       tag,
+        String    name)
+    {
+        if (tag == rfc822Name || tag == dNSName || tag == uniformResourceIdentifier)
+        {
+            this.tag = tag;
+            this.obj = new DERIA5String(name);
+        }
+        else if (tag == registeredID)
+        {
+            this.tag = tag;
+            this.obj = new DERObjectIdentifier(name);
+        }
+        else
+        {
+            throw new IllegalArgumentException("can't process String for tag: " + tag);
+        }
+    }
+    
+    public static GeneralName getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof GeneralName)
+        {
+            return (GeneralName)obj;
+        }
+
+        if (obj instanceof ASN1TaggedObject)
+        {
+            ASN1TaggedObject    tagObj = (ASN1TaggedObject)obj;
+            int                 tag = tagObj.getTagNo();
+
+            switch (tag)
+            {
+            case otherName:
+                return new GeneralName(ASN1Sequence.getInstance(tagObj, false), tag);
+            case rfc822Name:
+                return new GeneralName(DERIA5String.getInstance(tagObj, false), tag);
+            case dNSName:
+                return new GeneralName(DERIA5String.getInstance(tagObj, false), tag);
+            case x400Address:
+                throw new IllegalArgumentException("unknown tag: " + tag);
+            case directoryName:
+                return new GeneralName(ASN1Sequence.getInstance(tagObj, true), tag);
+            case ediPartyName:
+                return new GeneralName(ASN1Sequence.getInstance(tagObj, false), tag);
+            case uniformResourceIdentifier:
+                return new GeneralName(DERIA5String.getInstance(tagObj, false), tag);
+            case iPAddress:
+                return new GeneralName(ASN1OctetString.getInstance(tagObj, false), tag);
+            case registeredID:
+                return new GeneralName(DERObjectIdentifier.getInstance(tagObj, false), tag);
+            }
+        }
+
+        throw new IllegalArgumentException("unknown object in getInstance");
+    }
+
+    public static GeneralName getInstance(
+        ASN1TaggedObject tagObj,
+        boolean          explicit)
+    {
+        return GeneralName.getInstance(ASN1TaggedObject.getInstance(tagObj, true));
+    }
+
+    public int getTagNo()
+    {
+        return tag;
+    }
+
+    public DEREncodable getName()
+    {
+        return obj;
+    }
+
+    public DERObject toASN1Object()
+    {
+        if (tag == directoryName)       // directoryName is explicitly tagged as it is a CHOICE
+        {
+            return new DERTaggedObject(true, tag, obj);
+        }
+        else
+        {
+            return new DERTaggedObject(false, tag, obj);
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java
new file mode 100644
index 0000000..d2f8d7d
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java
@@ -0,0 +1,76 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+public class GeneralNames
+    extends ASN1Encodable
+{
+    ASN1Sequence            seq;
+
+    public static GeneralNames getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof GeneralNames)
+        {
+            return (GeneralNames)obj;
+        }
+
+        if (obj instanceof ASN1Sequence)
+        {
+            return new GeneralNames((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    public static GeneralNames getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    /**
+     * Construct a GeneralNames object containing one GeneralName.
+     * 
+     * @param name the name to be contained.
+     */
+    public GeneralNames(
+        GeneralName  name)
+    {
+        this.seq = new DERSequence(name);
+    }
+    
+    public GeneralNames(
+        ASN1Sequence  seq)
+    {
+        this.seq = seq;
+    }
+
+    public GeneralName[] getNames()
+    {
+        GeneralName[]   names = new GeneralName[seq.size()];
+        
+        for (int i = 0; i != seq.size(); i++)
+        {
+            names[i] = GeneralName.getInstance(seq.getObjectAt(i));
+        }
+        
+        return names;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * GeneralNames ::= SEQUENCE SIZE {1..MAX} OF GeneralName
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        return seq;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/GeneralSubtree.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/GeneralSubtree.java
new file mode 100644
index 0000000..e3e4240
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/GeneralSubtree.java
@@ -0,0 +1,195 @@
+package org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * Class for containing a restriction object subtrees in NameConstraints. See
+ * RFC 3280.
+ * 
+ * <pre>
+ *       
+ *       GeneralSubtree ::= SEQUENCE 
+ *       {
+ *         base                    GeneralName,
+ *         minimum         [0]     BaseDistance DEFAULT 0,
+ *         maximum         [1]     BaseDistance OPTIONAL 
+ *       }
+ * </pre>
+ * 
+ * @see org.bouncycastle.asn1.x509.NameConstraints
+ * 
+ */
+public class GeneralSubtree 
+    extends ASN1Encodable 
+{
+    private static final BigInteger ZERO = BigInteger.valueOf(0);
+
+    private GeneralName base;
+
+    private DERInteger minimum;
+
+    private DERInteger maximum;
+
+    public GeneralSubtree(
+        ASN1Sequence seq) 
+    {
+        base = GeneralName.getInstance(seq.getObjectAt(0));
+
+        switch (seq.size()) 
+        {
+        case 1:
+            break;
+        case 2:
+            ASN1TaggedObject o = ASN1TaggedObject.getInstance(seq.getObjectAt(1));
+            switch (o.getTagNo()) 
+            {
+            case 0:
+                minimum = DERInteger.getInstance(o, false);
+                break;
+            case 1:
+                maximum = DERInteger.getInstance(o, false);
+                break;
+            default:
+                throw new IllegalArgumentException("Bad tag number: "
+                        + o.getTagNo());
+            }
+            break;
+        case 3:
+            minimum = DERInteger.getInstance(ASN1TaggedObject.getInstance(seq.getObjectAt(1)));
+            maximum = DERInteger.getInstance(ASN1TaggedObject.getInstance(seq.getObjectAt(2)));
+            break;
+        default:
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + seq.size());
+        }
+    }
+
+    /**
+     * Constructor from a given details.
+     * 
+     * According RFC 3280, the minimum and maximum fields are not used with any
+     * name forms, thus minimum MUST be zero, and maximum MUST be absent.
+     * <p>
+     * If minimum is <code>null</code>, zero is assumed, if
+     * maximum is <code>null</code>, maximum is absent.
+     * 
+     * @param base
+     *            A restriction.
+     * @param minimum
+     *            Minimum
+     * 
+     * @param maximum
+     *            Maximum
+     */
+    public GeneralSubtree(
+        GeneralName base,
+        BigInteger minimum,
+        BigInteger maximum)
+    {
+        this.base = base;
+        if (maximum != null)
+        {
+            this.maximum = new DERInteger(maximum);
+        }
+        if (minimum == null)
+        {
+            this.minimum = null;
+        }
+        else
+        {
+            this.minimum = new DERInteger(minimum);
+        }
+    }
+
+    public static GeneralSubtree getInstance(
+        ASN1TaggedObject o,
+        boolean explicit)
+    {
+        return new GeneralSubtree(ASN1Sequence.getInstance(o, explicit));
+    }
+
+    public static GeneralSubtree getInstance(
+        Object obj)
+    {
+        if (obj == null)
+        {
+            return null;
+        }
+
+        if (obj instanceof GeneralSubtree)
+        {
+            return (GeneralSubtree) obj;
+        }
+
+        return new GeneralSubtree(ASN1Sequence.getInstance(obj));
+    }
+
+    public GeneralName getBase()
+    {
+        return base;
+    }
+
+    public BigInteger getMinimum()
+    {
+        if (minimum == null)
+        {
+            return ZERO;
+        }
+
+        return minimum.getValue();
+    }
+
+    public BigInteger getMaximum()
+    {
+        if (maximum == null)
+        {
+            return null;
+        }
+
+        return maximum.getValue();
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * 
+     * Returns:
+     * 
+     * <pre>
+     *       GeneralSubtree ::= SEQUENCE 
+     *       {
+     *         base                    GeneralName,
+     *         minimum         [0]     BaseDistance DEFAULT 0,
+     *         maximum         [1]     BaseDistance OPTIONAL 
+     *       }
+     * </pre>
+     * 
+     * @return a DERObject
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(base);
+
+        if (minimum != null && !minimum.getValue().equals(ZERO))
+        {
+            v.add(new DERTaggedObject(false, 0, minimum));
+        }
+
+        if (maximum != null)
+        {
+            v.add(new DERTaggedObject(false, 1, maximum));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/Holder.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/Holder.java
new file mode 100644
index 0000000..8b9a08c
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/Holder.java
@@ -0,0 +1,126 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * The Holder object.
+ * <pre>
+ *  Holder ::= SEQUENCE {
+ *        baseCertificateID   [0] IssuerSerial OPTIONAL,
+ *                 -- the issuer and serial number of
+ *                 -- the holder's Public Key Certificate
+ *        entityName          [1] GeneralNames OPTIONAL,
+ *                 -- the name of the claimant or role
+ *        objectDigestInfo    [2] ObjectDigestInfo OPTIONAL
+ *                 -- used to directly authenticate the holder,
+ *                 -- for example, an executable
+ *  }
+ * </pre>
+ */
+public class Holder
+    extends ASN1Encodable
+{
+    IssuerSerial        baseCertificateID;
+    GeneralNames        entityName;
+    ObjectDigestInfo    objectDigestInfo;
+
+    public static Holder getInstance(
+        Object  obj)
+    {
+        if (obj instanceof Holder)
+        {
+            return (Holder)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new Holder((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public Holder(
+        ASN1Sequence    seq)
+    {
+        if (seq.size() > 3)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + seq.size());
+        }
+
+        for (int i = 0; i != seq.size(); i++)
+        {
+            ASN1TaggedObject    tObj = ASN1TaggedObject.getInstance(seq.getObjectAt(i));
+            
+            switch (tObj.getTagNo())
+            {
+            case 0:
+                baseCertificateID = IssuerSerial.getInstance(tObj, false);
+                break;
+            case 1:
+                entityName = GeneralNames.getInstance(tObj, false);
+                break;
+            case 2:
+                objectDigestInfo = ObjectDigestInfo.getInstance(tObj, false);
+                break;
+            default:
+                throw new IllegalArgumentException("unknown tag in Holder");
+            }
+        }
+    }
+    
+    public Holder(
+        IssuerSerial    baseCertificateID)
+    {
+        this.baseCertificateID = baseCertificateID;
+    }
+    
+    public Holder(
+        GeneralNames    entityName)
+    {
+        this.entityName = entityName;
+    }
+    
+    public IssuerSerial getBaseCertificateID()
+    {
+        return baseCertificateID;
+    }
+    
+    public GeneralNames getEntityName()
+    {
+        return entityName;
+    }
+    
+    public ObjectDigestInfo getObjectDigestInfo()
+    {
+        return objectDigestInfo;
+    }
+    
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        if (baseCertificateID != null)
+        {
+            v.add(new DERTaggedObject(false, 0, baseCertificateID));
+        }
+
+        if (entityName != null)
+        {
+            v.add(new DERTaggedObject(false, 1, entityName));
+        }
+
+        if (objectDigestInfo != null)
+        {
+            v.add(new DERTaggedObject(false, 2, objectDigestInfo));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/IetfAttrSyntax.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/IetfAttrSyntax.java
new file mode 100644
index 0000000..07e07cf
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/IetfAttrSyntax.java
@@ -0,0 +1,174 @@
+package org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.DERUTF8String;
+
+/**
+ * Implementation of <code>IetfAttrSyntax</code> as specified by RFC3281.
+ */
+public class IetfAttrSyntax
+    extends ASN1Encodable
+{
+    public static final int VALUE_OCTETS    = 1;
+    public static final int VALUE_OID       = 2;
+    public static final int VALUE_UTF8      = 3;
+    GeneralNames            policyAuthority = null;
+    Vector                  values          = new Vector();
+    int                     valueChoice     = -1;
+
+    /**
+     *  
+     */
+    public IetfAttrSyntax(ASN1Sequence seq)
+    {
+        int i = 0;
+
+        if (seq.getObjectAt(0) instanceof ASN1TaggedObject)
+        {
+            policyAuthority = GeneralNames.getInstance(((ASN1TaggedObject)seq.getObjectAt(0)), false);
+            i++;
+        }
+        else if (seq.size() == 2)
+        { // VOMS fix
+            policyAuthority = GeneralNames.getInstance(seq.getObjectAt(0));
+            i++;
+        }
+
+        if (!(seq.getObjectAt(i) instanceof ASN1Sequence))
+        {
+            throw new IllegalArgumentException("Non-IetfAttrSyntax encoding");
+        }
+
+        seq = (ASN1Sequence)seq.getObjectAt(i);
+
+        for (Enumeration e = seq.getObjects(); e.hasMoreElements();)
+        {
+            DERObject obj = (DERObject)e.nextElement();
+            int type;
+
+            if (obj instanceof DERObjectIdentifier)
+            {
+                type = VALUE_OID;
+            }
+            else if (obj instanceof DERUTF8String)
+            {
+                type = VALUE_UTF8;
+            }
+            else if (obj instanceof DEROctetString)
+            {
+                type = VALUE_OCTETS;
+            }
+            else
+            {
+                throw new IllegalArgumentException("Bad value type encoding IetfAttrSyntax");
+            }
+
+            if (valueChoice < 0)
+            {
+                valueChoice = type;
+            }
+
+            if (type != valueChoice)
+            {
+                throw new IllegalArgumentException("Mix of value types in IetfAttrSyntax");
+            }
+
+            values.addElement(obj);
+        }
+    }
+
+    public GeneralNames getPolicyAuthority()
+    {
+        return policyAuthority;
+    }
+
+    public int getValueType()
+    {
+        return valueChoice;
+    }
+
+    public Object[] getValues()
+    {
+        if (this.getValueType() == VALUE_OCTETS)
+        {
+            ASN1OctetString[] tmp = new ASN1OctetString[values.size()];
+            
+            for (int i = 0; i != tmp.length; i++)
+            {
+                tmp[i] = (ASN1OctetString)values.elementAt(i);
+            }
+            
+            return tmp;
+        }
+        else if (this.getValueType() == VALUE_OID)
+        {
+            DERObjectIdentifier[] tmp = new DERObjectIdentifier[values.size()];
+            
+            for (int i = 0; i != tmp.length; i++)
+            {
+                tmp[i] = (DERObjectIdentifier)values.elementAt(i);
+            }
+            
+            return tmp;
+        }
+        else
+        {
+            DERUTF8String[] tmp = new DERUTF8String[values.size()];
+            
+            for (int i = 0; i != tmp.length; i++)
+            {
+                tmp[i] = (DERUTF8String)values.elementAt(i);
+            }
+            
+            return tmp;
+        }
+    }
+
+    /**
+     * 
+     * <pre>
+     * 
+     *  IetfAttrSyntax ::= SEQUENCE {
+     *    policyAuthority [0] GeneralNames OPTIONAL,
+     *    values SEQUENCE OF CHOICE {
+     *      octets OCTET STRING,
+     *      oid OBJECT IDENTIFIER,
+     *      string UTF8String
+     *    }
+     *  }
+     *  
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        if (policyAuthority != null)
+        {
+            v.add(new DERTaggedObject(0, policyAuthority));
+        }
+
+        ASN1EncodableVector v2 = new ASN1EncodableVector();
+
+        for (Enumeration i = values.elements(); i.hasMoreElements();)
+        {
+            v2.add((ASN1Encodable)i.nextElement());
+        }
+
+        v.add(new DERSequence(v2));
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/IssuerSerial.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/IssuerSerial.java
new file mode 100644
index 0000000..ceb639f
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/IssuerSerial.java
@@ -0,0 +1,106 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+public class IssuerSerial
+    extends ASN1Encodable
+{
+    GeneralNames            issuer;
+    DERInteger              serial;
+    DERBitString            issuerUID;
+
+    public static IssuerSerial getInstance(
+            Object  obj)
+    {
+        if (obj == null || obj instanceof IssuerSerial)
+        {
+            return (IssuerSerial)obj;
+        }
+
+        if (obj instanceof ASN1Sequence)
+        {
+            return new IssuerSerial((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    public static IssuerSerial getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+    
+    public IssuerSerial(
+        ASN1Sequence    seq)
+    {
+        if (seq.size() != 2 && seq.size() != 3)
+        {
+            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+        }
+        
+        issuer = GeneralNames.getInstance(seq.getObjectAt(0));
+        serial = DERInteger.getInstance(seq.getObjectAt(1));
+
+        if (seq.size() == 3)
+        {
+            issuerUID = DERBitString.getInstance(seq.getObjectAt(2));
+        }
+    }
+    
+    public IssuerSerial(
+        GeneralNames    issuer,
+        DERInteger      serial)
+    {
+        this.issuer = issuer;
+        this.serial = serial;
+    }
+
+    public GeneralNames getIssuer()
+    {
+        return issuer;
+    }
+
+    public DERInteger getSerial()
+    {
+        return serial;
+    }
+
+    public DERBitString getIssuerUID()
+    {
+        return issuerUID;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  IssuerSerial  ::=  SEQUENCE {
+     *       issuer         GeneralNames,
+     *       serial         CertificateSerialNumber,
+     *       issuerUID      UniqueIdentifier OPTIONAL
+     *  }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(issuer);
+        v.add(serial);
+
+        if (issuerUID != null)
+        {
+            v.add(issuerUID);
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java
new file mode 100644
index 0000000..07e468f
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java
@@ -0,0 +1,110 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERBoolean;
+import org.bouncycastle.asn1.DERObject;
+
+/**
+ * IssuingDistributionPoint ::= SEQUENCE {
+ *      distributionPoint          [0] DistributionPointName OPTIONAL,
+ *      onlyContainsUserCerts      [1] BOOLEAN DEFAULT FALSE,
+ *      onlyContainsCACerts        [2] BOOLEAN DEFAULT FALSE,
+ *      onlySomeReasons            [3] ReasonFlags OPTIONAL,
+ *      indirectCRL                [4] BOOLEAN DEFAULT FALSE,
+ *      onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE }
+ */
+public class IssuingDistributionPoint
+    extends ASN1Encodable
+{
+    private boolean         onlyContainsUserCerts;
+    private boolean         onlyContainsCACerts;
+    private boolean         indirectCRL;
+    private boolean         onlyContainsAttributeCerts;
+
+    private ASN1Sequence    seq;
+
+    public static IssuingDistributionPoint getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static IssuingDistributionPoint getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof IssuingDistributionPoint)
+        {
+            return (IssuingDistributionPoint)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new IssuingDistributionPoint((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    /**
+     * Constructor from ASN1Sequence
+     */
+    public IssuingDistributionPoint(
+        ASN1Sequence  seq)
+    {
+        this.seq = seq;
+
+        for (int i = 0; i != seq.size(); i++)
+        {
+            ASN1TaggedObject  o = ASN1TaggedObject.getInstance(seq.getObjectAt(i));
+
+            switch (o.getTagNo())
+            {
+            case 0:
+                break;
+            case 1:
+                onlyContainsUserCerts = DERBoolean.getInstance(o, false).isTrue();
+                break;
+            case 2:
+                onlyContainsCACerts = DERBoolean.getInstance(o, false).isTrue();
+                break;
+            case 3:
+                break;
+            case 4:
+                indirectCRL = DERBoolean.getInstance(o, false).isTrue();
+                break;
+            case 5:
+                onlyContainsAttributeCerts = DERBoolean.getInstance(o, false).isTrue();
+                break;
+            default:
+                throw new IllegalArgumentException("unknown tag in IssuingDistributionPoint");
+            }
+        }
+    }
+
+    public boolean onlyContainsUserCerts()
+    {
+        return onlyContainsUserCerts;
+    }
+
+    public boolean onlyContainsCACerts()
+    {
+        return onlyContainsCACerts;
+    }
+
+    public boolean isIndirectCRL()
+    {
+        return indirectCRL;
+    }
+
+    public boolean onlyContainsAttributeCerts()
+    {
+        return onlyContainsAttributeCerts;
+    }
+
+    public DERObject toASN1Object()
+    {
+        return seq;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/KeyPurposeId.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/KeyPurposeId.java
new file mode 100644
index 0000000..b247e09
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/KeyPurposeId.java
@@ -0,0 +1,37 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+/**
+ * The KeyPurposeId object.
+ * <pre>
+ *     KeyPurposeId ::= OBJECT IDENTIFIER
+ * </pre>
+ */
+public class KeyPurposeId
+    extends DERObjectIdentifier
+{
+    private static final String id_kp = "1.3.6.1.5.5.7.3";
+
+    private KeyPurposeId(
+        String  id)
+    {
+        super(id);
+    }
+
+    public static final KeyPurposeId anyExtendedKeyUsage = new KeyPurposeId(X509Extensions.ExtendedKeyUsage.getId() + ".0");
+    public static final KeyPurposeId id_kp_serverAuth = new KeyPurposeId(id_kp + ".1");
+    public static final KeyPurposeId id_kp_clientAuth = new KeyPurposeId(id_kp + ".2");
+    public static final KeyPurposeId id_kp_codeSigning = new KeyPurposeId(id_kp + ".3");
+    public static final KeyPurposeId id_kp_emailProtection = new KeyPurposeId(id_kp + ".4");
+    public static final KeyPurposeId id_kp_ipsecEndSystem = new KeyPurposeId(id_kp + ".5");
+    public static final KeyPurposeId id_kp_ipsecTunnel = new KeyPurposeId(id_kp + ".6");
+    public static final KeyPurposeId id_kp_ipsecUser = new KeyPurposeId(id_kp + ".7");
+    public static final KeyPurposeId id_kp_timeStamping = new KeyPurposeId(id_kp + ".8");
+    public static final KeyPurposeId id_kp_OCSPSigning = new KeyPurposeId(id_kp + ".9");
+
+    //
+    // microsoft key purpose ids
+    //
+    public static final KeyPurposeId id_kp_smartcardlogon = new KeyPurposeId("1.3.6.1.4.1.311.20.2.2");
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/KeyUsage.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/KeyUsage.java
new file mode 100644
index 0000000..e56424f
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/KeyUsage.java
@@ -0,0 +1,62 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.DERBitString;
+
+/**
+ * The KeyUsage object.
+ * <pre>
+ *    id-ce-keyUsage OBJECT IDENTIFIER ::=  { id-ce 15 }
+ *
+ *    KeyUsage ::= BIT STRING {
+ *         digitalSignature        (0),
+ *         nonRepudiation          (1),
+ *         keyEncipherment         (2),
+ *         dataEncipherment        (3),
+ *         keyAgreement            (4),
+ *         keyCertSign             (5),
+ *         cRLSign                 (6),
+ *         encipherOnly            (7),
+ *         decipherOnly            (8) }
+ * </pre>
+ */
+public class KeyUsage
+    extends DERBitString
+{
+    public static final int        digitalSignature = (1 << 7); 
+    public static final int        nonRepudiation   = (1 << 6);
+    public static final int        keyEncipherment  = (1 << 5);
+    public static final int        dataEncipherment = (1 << 4);
+    public static final int        keyAgreement     = (1 << 3);
+    public static final int        keyCertSign      = (1 << 2);
+    public static final int        cRLSign          = (1 << 1);
+    public static final int        encipherOnly     = (1 << 0);
+    public static final int        decipherOnly     = (1 << 15);
+
+    /**
+     * Basic constructor.
+     * 
+     * @param usage - the bitwise OR of the Key Usage flags giving the
+     * allowed uses for the key.
+     * e.g. (KeyUsage.keyEncipherment | KeyUsage.dataEncipherment)
+     */
+    public KeyUsage(
+        int usage)
+    {
+        super(getBytes(usage), getPadBits(usage));
+    }
+
+    public KeyUsage(
+        DERBitString usage)
+    {
+        super(usage.getBytes(), usage.getPadBits());
+    }
+
+    public String toString()
+    {
+        if (data.length == 1)
+        {
+            return "KeyUsage: 0x" + Integer.toHexString(data[0] & 0xff);
+        }
+        return "KeyUsage: 0x" + Integer.toHexString((data[1] & 0xff) << 8 | (data[0] & 0xff));
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/NameConstraints.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/NameConstraints.java
new file mode 100644
index 0000000..1383d39
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/NameConstraints.java
@@ -0,0 +1,104 @@
+package org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+public class NameConstraints
+    extends ASN1Encodable
+{
+    private ASN1Sequence permitted, excluded;
+
+    public NameConstraints(ASN1Sequence seq)
+    {
+        Enumeration e = seq.getObjects();
+        while (e.hasMoreElements())
+        {
+            ASN1TaggedObject o = ASN1TaggedObject.getInstance(e.nextElement());
+            switch (o.getTagNo())
+            {
+            case 0:
+                permitted = ASN1Sequence.getInstance(o, false);
+                break;
+            case 1:
+                excluded = ASN1Sequence.getInstance(o, false);
+                break;
+            }
+        }
+    }
+
+    /**
+     * Constructor from a given details.
+     * 
+     * <p>
+     * permitted and excluded are Vectors of GeneralSubtree objects.
+     * 
+     * @param permitted
+     *            Permitted subtrees
+     * @param excluded
+     *            Excludes subtrees
+     */
+    public NameConstraints(
+        Vector permitted,
+        Vector excluded)
+    {
+        if (permitted != null)
+        {
+            this.permitted = createSequence(permitted);
+        }
+        if (excluded != null)
+        {
+            this.excluded = createSequence(excluded);
+        }
+    }
+
+    private DERSequence createSequence(Vector subtree)
+    {
+        ASN1EncodableVector vec = new ASN1EncodableVector();
+        Enumeration e = subtree.elements(); 
+        while (e.hasMoreElements())
+        {
+            vec.add((GeneralSubtree)e.nextElement());
+        }
+        
+        return new DERSequence(vec);
+    }
+
+    public ASN1Sequence getPermittedSubtrees() 
+    {
+        return permitted;
+    }
+
+    public ASN1Sequence getExcludedSubtrees() 
+    {
+        return excluded;
+    }
+
+    /*
+     * NameConstraints ::= SEQUENCE { permittedSubtrees [0] GeneralSubtrees
+     * OPTIONAL, excludedSubtrees [1] GeneralSubtrees OPTIONAL }
+     */
+    public DERObject toASN1Object() 
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        if (permitted != null) 
+        {
+            v.add(new DERTaggedObject(false, 0, permitted));
+        }
+
+        if (excluded != null) 
+        {
+            v.add(new DERTaggedObject(false, 1, excluded));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/NoticeReference.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/NoticeReference.java
new file mode 100644
index 0000000..0bc639a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/NoticeReference.java
@@ -0,0 +1,155 @@
+
+package org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+/**
+ * <code>NoticeReference</code> class, used in
+ * <code>CertificatePolicies</code> X509 V3 extensions
+ * (in policy qualifiers).
+ * 
+ * <pre>
+ *  NoticeReference ::= SEQUENCE {
+ *      organization     DisplayText,
+ *      noticeNumbers    SEQUENCE OF INTEGER }
+ *
+ * </pre> 
+ * 
+ * @see PolicyQualifierInfo
+ * @see PolicyInformation
+ */
+public class NoticeReference 
+    extends ASN1Encodable
+{
+   private DisplayText organization;
+   private ASN1Sequence noticeNumbers;
+
+   /**
+    * Creates a new <code>NoticeReference</code> instance.
+    *
+    * @param orgName a <code>String</code> value
+    * @param numbers a <code>Vector</code> value
+    */
+   public NoticeReference(
+       String orgName,
+       Vector numbers) 
+   {
+      organization = new DisplayText(orgName);
+
+      Object o = numbers.elementAt(0);
+
+      ASN1EncodableVector av = new ASN1EncodableVector();
+      if (o instanceof Integer)
+      {
+         Enumeration it = numbers.elements();
+
+         while (it.hasMoreElements())
+         {
+            Integer nm = (Integer) it.nextElement();
+               DERInteger di = new DERInteger(nm.intValue());
+            av.add (di);
+         }
+      }
+
+      noticeNumbers = new DERSequence(av);
+   }
+
+   /**
+    * Creates a new <code>NoticeReference</code> instance.
+    *
+    * @param orgName a <code>String</code> value
+    * @param numbers an <code>ASN1EncodableVector</code> value
+    */
+   public NoticeReference(
+       String orgName, 
+       ASN1Sequence numbers) 
+   {
+       organization = new DisplayText (orgName);
+       noticeNumbers = numbers;
+   }
+
+   /**
+    * Creates a new <code>NoticeReference</code> instance.
+    *
+    * @param displayTextType an <code>int</code> value
+    * @param orgName a <code>String</code> value
+    * @param numbers an <code>ASN1EncodableVector</code> value
+    */
+   public NoticeReference(
+       int displayTextType,
+       String orgName,
+       ASN1Sequence numbers) 
+   {
+       organization = new DisplayText(displayTextType, 
+                                     orgName);
+       noticeNumbers = numbers;
+   }
+
+   /**
+    * Creates a new <code>NoticeReference</code> instance.
+    * <p>Useful for reconstructing a <code>NoticeReference</code>
+    * instance from its encodable/encoded form. 
+    *
+    * @param as an <code>ASN1Sequence</code> value obtained from either
+    * calling @{link toASN1Object()} for a <code>NoticeReference</code>
+    * instance or from parsing it from a DER-encoded stream. 
+    */
+   public NoticeReference(
+       ASN1Sequence as) 
+   {
+       if (as.size() != 2)
+       {
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + as.size());
+       }
+
+       organization = DisplayText.getInstance(as.getObjectAt(0));
+       noticeNumbers = ASN1Sequence.getInstance(as.getObjectAt(1));
+   }
+
+   public static NoticeReference getInstance(
+       Object as) 
+   {
+      if (as instanceof NoticeReference)
+      {
+          return (NoticeReference)as;
+      }
+      else if (as instanceof ASN1Sequence)
+      {
+          return new NoticeReference((ASN1Sequence)as);
+      }
+
+      throw new IllegalArgumentException("unknown object in getInstance.");
+   }
+   
+   public DisplayText getOrganization()
+   {
+       return organization;
+   }
+   
+   public ASN1Sequence getNoticeNumbers()
+   {
+       return noticeNumbers;
+   }
+   
+   /**
+    * Describe <code>toASN1Object</code> method here.
+    *
+    * @return a <code>DERObject</code> value
+    */
+   public DERObject toASN1Object() 
+   {
+      ASN1EncodableVector av = new ASN1EncodableVector();
+      av.add (organization);
+      av.add (noticeNumbers);
+      return new DERSequence (av);
+   }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/ObjectDigestInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/ObjectDigestInfo.java
new file mode 100644
index 0000000..048922b
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/ObjectDigestInfo.java
@@ -0,0 +1,127 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DEREnumerated;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+
+public class ObjectDigestInfo
+    extends ASN1Encodable
+{
+    DEREnumerated digestedObjectType;
+
+    DERObjectIdentifier otherObjectTypeID;
+
+    AlgorithmIdentifier digestAlgorithm;
+
+    DERBitString objectDigest;
+
+    public static ObjectDigestInfo getInstance(
+            Object  obj)
+    {
+        if (obj == null || obj instanceof ObjectDigestInfo)
+        {
+            return (ObjectDigestInfo)obj;
+        }
+
+        if (obj instanceof ASN1Sequence)
+        {
+            return new ObjectDigestInfo((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    public static ObjectDigestInfo getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+    
+    public ObjectDigestInfo(ASN1Sequence seq)
+    {
+        if (seq.size() > 4 || seq.size() < 3)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + seq.size());
+        }
+
+        digestedObjectType = DEREnumerated.getInstance(seq.getObjectAt(0));
+
+        int offset = 0;
+
+        if (seq.size() == 4)
+        {
+            otherObjectTypeID = DERObjectIdentifier.getInstance(seq.getObjectAt(1));
+            offset++;
+        }
+
+        digestAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1 + offset));
+
+        objectDigest = DERBitString.getInstance(seq.getObjectAt(2 + offset));
+    }
+
+    public DEREnumerated getDigestedObjectType()
+    {
+        return digestedObjectType;
+    }
+
+    public DERObjectIdentifier getOtherObjectTypeID()
+    {
+        return otherObjectTypeID;
+    }
+
+    public AlgorithmIdentifier getDigestAlgorithm()
+    {
+        return digestAlgorithm;
+    }
+
+    public DERBitString getObjectDigest()
+    {
+        return objectDigest;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * 
+     * <pre>
+     * 
+     *   ObjectDigestInfo ::= SEQUENCE {
+     *        digestedObjectType  ENUMERATED {
+     *                publicKey            (0),
+     *                publicKeyCert        (1),
+     *                otherObjectTypes     (2) },
+     *                        -- otherObjectTypes MUST NOT
+     *                        -- be used in this profile
+     *        otherObjectTypeID   OBJECT IDENTIFIER OPTIONAL,
+     *        digestAlgorithm     AlgorithmIdentifier,
+     *        objectDigest        BIT STRING
+     *   }
+     *  
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(digestedObjectType);
+
+        if (otherObjectTypeID != null)
+        {
+            v.add(otherObjectTypeID);
+        }
+
+        v.add(digestAlgorithm);
+        v.add(objectDigest);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/PolicyInformation.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/PolicyInformation.java
new file mode 100644
index 0000000..b4373b0
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/PolicyInformation.java
@@ -0,0 +1,87 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+
+public class PolicyInformation
+    extends ASN1Encodable
+{
+    private DERObjectIdentifier   policyIdentifier;
+    private ASN1Sequence          policyQualifiers;
+
+    public PolicyInformation(
+        ASN1Sequence seq)
+    {
+        if (seq.size() < 1 || seq.size() > 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + seq.size());
+        }
+
+        policyIdentifier = DERObjectIdentifier.getInstance(seq.getObjectAt(0));
+
+        if (seq.size() > 1)
+        {
+            policyQualifiers = ASN1Sequence.getInstance(seq.getObjectAt(1));
+        }
+    }
+
+    public PolicyInformation(
+        DERObjectIdentifier policyIdentifier)
+    {
+        this.policyIdentifier = policyIdentifier;
+    }
+
+    public PolicyInformation(
+        DERObjectIdentifier policyIdentifier,
+        ASN1Sequence        policyQualifiers)
+    {
+        this.policyIdentifier = policyIdentifier;
+        this.policyQualifiers = policyQualifiers;
+    }
+
+    public static PolicyInformation getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof PolicyInformation)
+        {
+            return (PolicyInformation)obj;
+        }
+
+        return new PolicyInformation(ASN1Sequence.getInstance(obj));
+    }
+
+    public DERObjectIdentifier getPolicyIdentifier()
+    {
+        return policyIdentifier;
+    }
+    
+    public ASN1Sequence getPolicyQualifiers()
+    {
+        return policyQualifiers;
+    }
+    
+    /* 
+     * PolicyInformation ::= SEQUENCE {
+     *      policyIdentifier   CertPolicyId,
+     *      policyQualifiers   SEQUENCE SIZE (1..MAX) OF
+     *              PolicyQualifierInfo OPTIONAL }
+     */ 
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+        
+        v.add(policyIdentifier);
+
+        if (policyQualifiers != null)
+        {
+            v.add(policyQualifiers);
+        }
+        
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/PolicyMappings.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/PolicyMappings.java
new file mode 100644
index 0000000..df78ec4
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/PolicyMappings.java
@@ -0,0 +1,68 @@
+package org.bouncycastle.asn1.x509;
+
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+
+/**
+ * PolicyMappings V3 extension, described in RFC3280.
+ * <pre>
+ *    PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE {
+ *      issuerDomainPolicy      CertPolicyId,
+ *      subjectDomainPolicy     CertPolicyId }
+ * </pre>
+ *
+ * @see <a href="http://www.faqs.org/rfc/rfc3280.txt">RFC 3280, section 4.2.1.6</a>
+ */
+public class PolicyMappings
+    extends ASN1Encodable
+{
+   ASN1Sequence seq = null;
+
+   /**
+    * Creates a new <code>PolicyMappings</code> instance.
+    *
+    * @param seq an <code>ASN1Sequence</code> constructed as specified
+    * in RFC 3280
+    */
+   public PolicyMappings (ASN1Sequence seq) 
+      {
+         this.seq = seq;
+      }
+
+   /**
+    * Creates a new <code>PolicyMappings</code> instance.
+    *
+    * @param mappings a <code>HashMap</code> value that maps
+    * <code>String</code> oids
+    * to other <code>String</code> oids. 
+    */
+   public PolicyMappings (Hashtable mappings) 
+      {
+         ASN1EncodableVector dev = new ASN1EncodableVector();
+         Enumeration it = mappings.keys();
+
+         while (it.hasMoreElements())
+         {
+            String idp = (String) it.nextElement();
+            String sdp = (String) mappings.get(idp);
+            ASN1EncodableVector dv = new ASN1EncodableVector();
+            dv.add(new DERObjectIdentifier(idp));
+            dv.add(new DERObjectIdentifier(sdp));
+            dev.add(new DERSequence(dv));
+         }
+
+         seq = new DERSequence(dev);
+      }
+
+   public DERObject toASN1Object() 
+      {
+         return seq;
+      }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/PolicyQualifierId.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/PolicyQualifierId.java
new file mode 100644
index 0000000..2678057
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/PolicyQualifierId.java
@@ -0,0 +1,31 @@
+
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+/**
+ * PolicyQualifierId, used in the CertificatePolicies
+ * X509V3 extension.
+ * 
+ * <pre>
+ *    id-qt          OBJECT IDENTIFIER ::=  { id-pkix 2 }
+ *    id-qt-cps      OBJECT IDENTIFIER ::=  { id-qt 1 }
+ *    id-qt-unotice  OBJECT IDENTIFIER ::=  { id-qt 2 }
+ *  PolicyQualifierId ::=
+ *       OBJECT IDENTIFIER (id-qt-cps | id-qt-unotice)
+ * </pre>
+ */
+public class PolicyQualifierId extends DERObjectIdentifier 
+{
+   private static final String id_qt = "1.3.6.1.5.5.7.2";
+
+   private PolicyQualifierId(String id) 
+      {
+         super(id);
+      }
+   
+   public static final PolicyQualifierId id_qt_cps =
+       new PolicyQualifierId(id_qt + ".1");
+   public static final PolicyQualifierId id_qt_unotice =
+       new PolicyQualifierId(id_qt + ".2");
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/PolicyQualifierInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/PolicyQualifierInfo.java
new file mode 100644
index 0000000..6e97f70
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/PolicyQualifierInfo.java
@@ -0,0 +1,114 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERIA5String;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+
+/**
+ * Policy qualifiers, used in the X509V3 CertificatePolicies
+ * extension.
+ * 
+ * <pre>
+ *   PolicyQualifierInfo ::= SEQUENCE {
+ *       policyQualifierId  PolicyQualifierId,
+ *       qualifier          ANY DEFINED BY policyQualifierId }
+ * </pre>
+ */
+public class PolicyQualifierInfo
+    extends ASN1Encodable
+{
+   private DERObjectIdentifier policyQualifierId;
+   private DEREncodable        qualifier;
+
+   /**
+    * Creates a new <code>PolicyQualifierInfo</code> instance.
+    *
+    * @param policyQualifierId a <code>PolicyQualifierId</code> value
+    * @param qualifier the qualifier, defined by the above field.
+    */
+   public PolicyQualifierInfo(
+       DERObjectIdentifier policyQualifierId,
+       DEREncodable qualifier) 
+   {
+      this.policyQualifierId = policyQualifierId;
+      this.qualifier = qualifier;
+   }
+
+   /**
+    * Creates a new <code>PolicyQualifierInfo</code> containing a
+    * cPSuri qualifier.
+    *
+    * @param cps the CPS (certification practice statement) uri as a
+    * <code>String</code>.
+    */
+   public PolicyQualifierInfo(
+       String cps) 
+   {
+      policyQualifierId = PolicyQualifierId.id_qt_cps;
+      qualifier = new DERIA5String (cps);
+   }
+
+   /**
+    * Creates a new <code>PolicyQualifierInfo</code> instance.
+    *
+    * @param as <code>PolicyQualifierInfo</code> X509 structure
+    * encoded as an ASN1Sequence. 
+    */
+   public PolicyQualifierInfo(
+       ASN1Sequence as)
+   {
+        if (as.size() != 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + as.size());
+        }
+
+        policyQualifierId = DERObjectIdentifier.getInstance(as.getObjectAt(0));
+        qualifier = as.getObjectAt(1);
+   }
+
+   public static PolicyQualifierInfo getInstance(
+       Object as) 
+   {
+        if (as instanceof PolicyQualifierInfo)
+        {
+            return (PolicyQualifierInfo)as;
+        }
+        else if (as instanceof ASN1Sequence)
+        {
+            return new PolicyQualifierInfo((ASN1Sequence)as);
+        }
+
+        throw new IllegalArgumentException("unknown object in getInstance.");
+   }
+
+
+   public DERObjectIdentifier getPolicyQualifierId()
+   {
+       return policyQualifierId;
+   }
+
+   public DEREncodable getQualifier()
+   {
+       return qualifier;
+   }
+   
+   /**
+    * Returns a DER-encodable representation of this instance. 
+    *
+    * @return a <code>DERObject</code> value
+    */
+   public DERObject toASN1Object() 
+   {
+      ASN1EncodableVector dev = new ASN1EncodableVector();
+      dev.add(policyQualifierId);
+      dev.add(qualifier);
+
+      return new DERSequence(dev);
+   }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java
new file mode 100644
index 0000000..0047f6a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java
@@ -0,0 +1,95 @@
+package org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+public class RSAPublicKeyStructure
+    extends ASN1Encodable
+{
+    private BigInteger  modulus;
+    private BigInteger  publicExponent;
+
+    public static RSAPublicKeyStructure getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static RSAPublicKeyStructure getInstance(
+        Object obj)
+    {
+        if(obj == null || obj instanceof RSAPublicKeyStructure) 
+        {
+            return (RSAPublicKeyStructure)obj;
+        }
+        
+        if(obj instanceof ASN1Sequence) 
+        {
+            return new RSAPublicKeyStructure((ASN1Sequence)obj);
+        }
+        
+        throw new IllegalArgumentException("Invalid RSAPublicKeyStructure: " + obj.getClass().getName());
+    }
+    
+    public RSAPublicKeyStructure(
+        BigInteger  modulus,
+        BigInteger  publicExponent)
+    {
+        this.modulus = modulus;
+        this.publicExponent = publicExponent;
+    }
+
+    public RSAPublicKeyStructure(
+        ASN1Sequence  seq)
+    {
+        if (seq.size() != 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + seq.size());
+        }
+
+        Enumeration e = seq.getObjects();
+
+        modulus = DERInteger.getInstance(e.nextElement()).getPositiveValue();
+        publicExponent = DERInteger.getInstance(e.nextElement()).getPositiveValue();
+    }
+
+    public BigInteger getModulus()
+    {
+        return modulus;
+    }
+
+    public BigInteger getPublicExponent()
+    {
+        return publicExponent;
+    }
+
+    /**
+     * This outputs the key in PKCS1v2 format.
+     * <pre>
+     *      RSAPublicKey ::= SEQUENCE {
+     *                          modulus INTEGER, -- n
+     *                          publicExponent INTEGER, -- e
+     *                      }
+     * </pre>
+     * <p>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(new DERInteger(getModulus()));
+        v.add(new DERInteger(getPublicExponent()));
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/ReasonFlags.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/ReasonFlags.java
new file mode 100644
index 0000000..612e2c5
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/ReasonFlags.java
@@ -0,0 +1,85 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.DERBitString;
+
+/**
+ * The ReasonFlags object.
+ * <pre>
+ * ReasonFlags ::= BIT STRING {
+ *      unused                  (0),
+ *      keyCompromise           (1),
+ *      cACompromise            (2),
+ *      affiliationChanged      (3),
+ *      superseded              (4),
+ *      cessationOfOperation    (5),
+ *      certificateHold         (6),
+ *      privilegeWithdrawn      (7),
+ *      aACompromise            (8) }
+ * </pre>
+ */
+public class ReasonFlags
+    extends DERBitString
+{
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int UNUSED                  = (1 << 7);
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int KEY_COMPROMISE          = (1 << 6);
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int CA_COMPROMISE           = (1 << 5);
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int AFFILIATION_CHANGED     = (1 << 4);
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int SUPERSEDED              = (1 << 3);
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int CESSATION_OF_OPERATION  = (1 << 2);
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int CERTIFICATE_HOLD        = (1 << 1);
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int PRIVILEGE_WITHDRAWN     = (1 << 0);
+    /**
+     * @deprecated use lower case version
+     */
+    public static final int AA_COMPROMISE           = (1 << 15);
+    
+    public static final int unused                  = (1 << 7);
+    public static final int keyCompromise           = (1 << 6);
+    public static final int cACompromise            = (1 << 5);
+    public static final int affiliationChanged      = (1 << 4);
+    public static final int superseded              = (1 << 3);
+    public static final int cessationOfOperation    = (1 << 2);
+    public static final int certificateHold         = (1 << 1);
+    public static final int privilegeWithdrawn      = (1 << 0);
+    public static final int aACompromise            = (1 << 15);
+
+    /**
+     * @param reasons - the bitwise OR of the Key Reason flags giving the
+     * allowed uses for the key.
+     */
+    public ReasonFlags(
+        int reasons)
+    {
+        super(getBytes(reasons), getPadBits(reasons));
+    }
+
+    public ReasonFlags(
+        DERBitString reasons)
+    {
+        super(reasons.getBytes(), reasons.getPadBits());
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/RoleSyntax.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/RoleSyntax.java
new file mode 100644
index 0000000..fe227d9
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/RoleSyntax.java
@@ -0,0 +1,236 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERString;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * Implementation of the RoleSyntax object as specified by the RFC3281.
+ * 
+ * <pre>
+ * RoleSyntax ::= SEQUENCE {
+ *                 roleAuthority  [0] GeneralNames OPTIONAL,
+ *                 roleName       [1] GeneralName
+ *           } 
+ * </pre>
+ */
+public class RoleSyntax 
+    extends ASN1Encodable
+{
+    private GeneralNames roleAuthority;
+    private GeneralName roleName;
+
+    /**
+     * RoleSyntax factory method.
+     * @param obj the object used to construct an instance of <code>
+     * RoleSyntax</code>. It must be an instance of <code>RoleSyntax
+     * </code> or <code>ASN1Sequence</code>.
+     * @return the instance of <code>RoleSyntax</code> built from the
+     * supplied object.
+     * @throws java.lang.IllegalArgumentException if the object passed
+     * to the factory is not an instance of <code>RoleSyntax</code> or
+     * <code>ASN1Sequence</code>.
+     */
+    public static RoleSyntax getInstance(
+        Object obj)
+    {
+        
+        if(obj == null || obj instanceof RoleSyntax)
+        {
+            return (RoleSyntax)obj;
+        }
+        else if(obj instanceof ASN1Sequence)
+        {
+            return new RoleSyntax((ASN1Sequence)obj);
+        }
+        throw new IllegalArgumentException("Unknown object in RoleSyntax factory.");
+    }
+    
+    /**
+     * Constructor.
+     * @param roleAuthority the role authority of this RoleSyntax.
+     * @param roleName    the role name of this RoleSyntax.
+     */
+    public RoleSyntax(
+        GeneralNames roleAuthority,
+        GeneralName roleName)
+    {
+        if(roleName == null || 
+                roleName.getTagNo() != GeneralName.uniformResourceIdentifier ||
+                ((DERString)roleName.getName()).getString().equals(""))
+        {
+            throw new IllegalArgumentException("the role name MUST be non empty and MUST " +
+                    "use the URI option of GeneralName");
+        }
+        this.roleAuthority = roleAuthority;
+        this.roleName = roleName;
+    }
+    
+    /**
+     * Constructor. Invoking this constructor is the same as invoking
+     * <code>new RoleSyntax(null, roleName)</code>.
+     * @param roleName    the role name of this RoleSyntax.
+     */
+    public RoleSyntax(
+        GeneralName roleName)
+    {
+        this(null, roleName);
+    }
+
+    /**
+     * Utility constructor. Takes a <code>String</code> argument representing
+     * the role name, builds a <code>GeneralName</code> to hold the role name
+     * and calls the constructor that takes a <code>GeneralName</code>.
+     * @param roleName
+     */
+    public RoleSyntax(
+        String roleName)
+    {
+        this(new GeneralName(GeneralName.uniformResourceIdentifier,
+                (roleName == null)? "": roleName));
+    }
+    
+    /**
+     * Constructor that builds an instance of <code>RoleSyntax</code> by
+     * extracting the encoded elements from the <code>ASN1Sequence</code>
+     * object supplied.
+     * @param seq    an instance of <code>ASN1Sequence</code> that holds
+     * the encoded elements used to build this <code>RoleSyntax</code>.
+     */
+    public RoleSyntax(
+        ASN1Sequence seq)
+    {
+        if (seq.size() < 1 || seq.size() > 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + seq.size());
+        }
+
+        for (int i = 0; i != seq.size(); i++)
+        {
+            ASN1TaggedObject taggedObject = ASN1TaggedObject.getInstance(seq.getObjectAt(i));
+            switch (taggedObject.getTagNo())
+            {
+            case 0:
+                roleAuthority = GeneralNames.getInstance(taggedObject, false);
+                break;
+            case 1:
+                roleName = GeneralName.getInstance(taggedObject, false);
+                break;
+            default:
+                throw new IllegalArgumentException("Unknown tag in RoleSyntax");
+            }
+        }
+    }
+
+    /**
+     * Gets the role authority of this RoleSyntax.
+     * @return    an instance of <code>GeneralNames</code> holding the
+     * role authority of this RoleSyntax.
+     */
+    public GeneralNames getRoleAuthority()
+    {
+        return this.roleAuthority;
+    }
+    
+    /**
+     * Gets the role name of this RoleSyntax.
+     * @return    an instance of <code>GeneralName</code> holding the
+     * role name of this RoleSyntax.
+     */
+    public GeneralName getRoleName()
+    {
+        return this.roleName;
+    }
+    
+    /**
+     * Gets the role name as a <code>java.lang.String</code> object.
+     * @return    the role name of this RoleSyntax represented as a 
+     * <code>java.lang.String</code> object.
+     */
+    public String getRoleNameAsString()
+    {
+        DERString str = (DERString)this.roleName.getName();
+        
+        return str.getString();
+    }
+    
+    /**
+     * Gets the role authority as a <code>String[]</code> object.
+     * @return the role authority of this RoleSyntax represented as a
+     * <code>String[]<code> array.
+     */
+    public String[] getRoleAuthorityAsString() 
+    {
+        if(roleAuthority == null) 
+        {
+            return new String[0];
+        }
+        
+        GeneralName[] names = roleAuthority.getNames();
+        String[] namesString = new String[names.length];
+        for(int i = 0; i < names.length; i++) 
+        {
+            DEREncodable value = names[i].getName();
+            if(value instanceof DERString)
+            {
+                namesString[i] = ((DERString)value).getString();
+            }
+            else
+            {
+                namesString[i] = value.toString();
+            }
+        }
+        return namesString;
+    }
+    
+    /**
+     * Implementation of the method <code>toASN1Object</code> as
+     * required by the superclass <code>ASN1Encodable</code>.
+     * 
+     * <pre>
+     * RoleSyntax ::= SEQUENCE {
+     *                 roleAuthority  [0] GeneralNames OPTIONAL,
+     *                 roleName       [1] GeneralName
+     *           } 
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+        if(this.roleAuthority != null)
+        {
+            v.add(new DERTaggedObject(false, 0, roleAuthority));
+        }
+        v.add(new DERTaggedObject(false, 1, roleName));
+        
+        return new DERSequence(v);
+    }
+    
+    public String toString() 
+    {
+        StringBuffer buff = new StringBuffer("Name: " + this.getRoleNameAsString() +
+                " - Auth: ");
+        if(this.roleAuthority == null || roleAuthority.getNames().length == 0)
+        {
+            buff.append("N/A");
+        }
+        else 
+        {
+            String[] names = this.getRoleAuthorityAsString();
+            buff.append('[').append(names[0]);
+            for(int i = 1; i < names.length; i++) 
+            {
+                    buff.append(", ").append(names[i]);
+            }
+            buff.append(']');
+        }
+        return buff.toString();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/SubjectDirectoryAttributes.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/SubjectDirectoryAttributes.java
new file mode 100644
index 0000000..3dede65
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/SubjectDirectoryAttributes.java
@@ -0,0 +1,144 @@
+package org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+/**
+ * This extension may contain further X.500 attributes of the subject. See also
+ * RFC 3039.
+ * 
+ * <pre>
+ *     SubjectDirectoryAttributes ::= Attributes
+ *     Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+ *     Attribute ::= SEQUENCE 
+ *     {
+ *       type AttributeType 
+ *       values SET OF AttributeValue 
+ *     }
+ *     
+ *     AttributeType ::= OBJECT IDENTIFIER
+ *     AttributeValue ::= ANY DEFINED BY AttributeType
+ * </pre>
+ * 
+ * @see org.bouncycastle.asn1.x509.X509Name for AttributeType ObjectIdentifiers.
+ */
+public class SubjectDirectoryAttributes 
+    extends ASN1Encodable
+{
+    private Vector attributes = new Vector();
+
+    public static SubjectDirectoryAttributes getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof SubjectDirectoryAttributes)
+        {
+            return (SubjectDirectoryAttributes)obj;
+        }
+
+        if (obj instanceof ASN1Sequence)
+        {
+            return new SubjectDirectoryAttributes((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * Constructor from ASN1Sequence.
+     * 
+     * The sequence is of type SubjectDirectoryAttributes:
+     * 
+     * <pre>
+     *      SubjectDirectoryAttributes ::= Attributes
+     *      Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+     *      Attribute ::= SEQUENCE 
+     *      {
+     *        type AttributeType 
+     *        values SET OF AttributeValue 
+     *      }
+     *      
+     *      AttributeType ::= OBJECT IDENTIFIER
+     *      AttributeValue ::= ANY DEFINED BY AttributeType
+     * </pre>
+     * 
+     * @param seq
+     *            The ASN.1 sequence.
+     */
+    public SubjectDirectoryAttributes(ASN1Sequence seq)
+    {
+        Enumeration e = seq.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            ASN1Sequence s = ASN1Sequence.getInstance(e.nextElement());
+            attributes.addElement(new Attribute(s));
+        }
+    }
+
+    /**
+     * Constructor from a vector of attributes.
+     * 
+     * The vector consists of attributes of type {@link Attribute Attribute}
+     * 
+     * @param attributes
+     *            The attributes.
+     * 
+     */
+    public SubjectDirectoryAttributes(Vector attributes)
+    {
+        Enumeration e = attributes.elements();
+
+        while (e.hasMoreElements())
+        {
+            this.attributes.addElement(e.nextElement());
+        }
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * 
+     * Returns:
+     * 
+     * <pre>
+     *      SubjectDirectoryAttributes ::= Attributes
+     *      Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+     *      Attribute ::= SEQUENCE 
+     *      {
+     *        type AttributeType 
+     *        values SET OF AttributeValue 
+     *      }
+     *      
+     *      AttributeType ::= OBJECT IDENTIFIER
+     *      AttributeValue ::= ANY DEFINED BY AttributeType
+     * </pre>
+     * 
+     * @return a DERObject
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector vec = new ASN1EncodableVector();
+        Enumeration e = attributes.elements();
+
+        while (e.hasMoreElements())
+        {
+
+            vec.add((Attribute)e.nextElement());
+        }
+
+        return new DERSequence(vec);
+    }
+
+    /**
+     * @return Returns the attributes.
+     */
+    public Vector getAttributes()
+    {
+        return attributes;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java
new file mode 100644
index 0000000..ca7ad42
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java
@@ -0,0 +1,90 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.SHA1Digest;
+
+/**
+ * The SubjectKeyIdentifier object.
+ * <pre>
+ * SubjectKeyIdentifier::= OCTET STRING
+ * </pre>
+ */
+public class SubjectKeyIdentifier
+    extends ASN1Encodable
+{
+    private byte[] keyidentifier;
+
+    public static SubjectKeyIdentifier getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1OctetString.getInstance(obj, explicit));
+    }
+
+    public static SubjectKeyIdentifier getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof SubjectKeyIdentifier) 
+        {
+            return (SubjectKeyIdentifier)obj;
+        }
+        
+        if (obj instanceof SubjectPublicKeyInfo) 
+        {
+            return new SubjectKeyIdentifier((SubjectPublicKeyInfo)obj);
+        }
+        
+        if (obj instanceof ASN1OctetString) 
+        {
+            return new SubjectKeyIdentifier((ASN1OctetString)obj);
+        }
+        
+        throw new IllegalArgumentException("Invalid SubjectKeyIdentifier: " + obj.getClass().getName());
+    }
+    
+    public SubjectKeyIdentifier(
+        byte[] keyid)
+    {
+        this.keyidentifier=keyid;
+    }
+
+    public SubjectKeyIdentifier(
+        ASN1OctetString  keyid)
+    {
+        this.keyidentifier=keyid.getOctets();
+
+    }
+
+    /**
+     *
+     * Calulates the keyidentifier using a SHA1 hash over the BIT STRING
+     * from SubjectPublicKeyInfo as defined in RFC2459.
+     *
+     **/
+    public SubjectKeyIdentifier(
+        SubjectPublicKeyInfo    spki)
+    {
+        Digest  digest = new SHA1Digest();
+        byte[]  resBuf = new byte[digest.getDigestSize()];
+
+        byte[] bytes = spki.getPublicKeyData().getBytes();
+        digest.update(bytes, 0, bytes.length);
+        digest.doFinal(resBuf, 0);
+        this.keyidentifier=resBuf;
+    }
+
+    public byte[] getKeyIdentifier()
+    {
+        return keyidentifier;
+    }
+
+    public DERObject toASN1Object()
+    {
+        return new DEROctetString(keyidentifier);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java
new file mode 100644
index 0000000..a733727
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java
@@ -0,0 +1,126 @@
+package org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+/**
+ * The object that contains the public key stored in a certficate.
+ * <p>
+ * The getEncoded() method in the public keys in the JCE produces a DER
+ * encoded one of these.
+ */
+public class SubjectPublicKeyInfo
+    extends ASN1Encodable
+{
+    private AlgorithmIdentifier     algId;
+    private DERBitString            keyData;
+
+    public static SubjectPublicKeyInfo getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static SubjectPublicKeyInfo getInstance(
+        Object  obj)
+    {
+        if (obj instanceof SubjectPublicKeyInfo)
+        {
+            return (SubjectPublicKeyInfo)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new SubjectPublicKeyInfo((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public SubjectPublicKeyInfo(
+        AlgorithmIdentifier algId,
+        DEREncodable        publicKey)
+    {
+        this.keyData = new DERBitString(publicKey);
+        this.algId = algId;
+    }
+
+    public SubjectPublicKeyInfo(
+        AlgorithmIdentifier algId,
+        byte[]              publicKey)
+    {
+        this.keyData = new DERBitString(publicKey);
+        this.algId = algId;
+    }
+
+    public SubjectPublicKeyInfo(
+        ASN1Sequence  seq)
+    {
+        if (seq.size() != 2)
+        {
+            throw new IllegalArgumentException("Bad sequence size: "
+                    + seq.size());
+        }
+
+        Enumeration         e = seq.getObjects();
+
+        this.algId = AlgorithmIdentifier.getInstance(e.nextElement());
+        this.keyData = DERBitString.getInstance(e.nextElement());
+    }
+
+    public AlgorithmIdentifier getAlgorithmId()
+    {
+        return algId;
+    }
+
+    /**
+     * for when the public key is an encoded object - if the bitstring
+     * can't be decoded this routine throws an IOException.
+     *
+     * @exception IOException - if the bit string doesn't represent a DER
+     * encoded object.
+     */
+    public DERObject getPublicKey()
+        throws IOException
+    {
+        ASN1InputStream         aIn = new ASN1InputStream(keyData.getBytes());
+
+        return aIn.readObject();
+    }
+
+    /**
+     * for when the public key is raw bits...
+     */
+    public DERBitString getPublicKeyData()
+    {
+        return keyData;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * SubjectPublicKeyInfo ::= SEQUENCE {
+     *                          algorithm AlgorithmIdentifier,
+     *                          publicKey BIT STRING }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(algId);
+        v.add(keyData);
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java
new file mode 100644
index 0000000..6c5afd8
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java
@@ -0,0 +1,212 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERGeneralizedTime;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.DERUTCTime;
+
+/**
+ * PKIX RFC-2459 - TBSCertList object.
+ * <pre>
+ * TBSCertList  ::=  SEQUENCE  {
+ *      version                 Version OPTIONAL,
+ *                                   -- if present, shall be v2
+ *      signature               AlgorithmIdentifier,
+ *      issuer                  Name,
+ *      thisUpdate              Time,
+ *      nextUpdate              Time OPTIONAL,
+ *      revokedCertificates     SEQUENCE OF SEQUENCE  {
+ *           userCertificate         CertificateSerialNumber,
+ *           revocationDate          Time,
+ *           crlEntryExtensions      Extensions OPTIONAL
+ *                                         -- if present, shall be v2
+ *                                }  OPTIONAL,
+ *      crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
+ *                                         -- if present, shall be v2
+ *                                }
+ * </pre>
+ */
+public class TBSCertList
+    extends ASN1Encodable
+{
+    public class CRLEntry
+        extends ASN1Encodable
+    {
+        ASN1Sequence  seq;
+
+        DERInteger          userCertificate;
+        Time                revocationDate;
+        X509Extensions      crlEntryExtensions;
+
+        public CRLEntry(
+            ASN1Sequence  seq)
+        {
+            if (seq.size() < 2 || seq.size() > 3)
+            {
+                throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+            }
+            
+            this.seq = seq;
+
+            userCertificate = DERInteger.getInstance(seq.getObjectAt(0));
+            revocationDate = Time.getInstance(seq.getObjectAt(1));
+            if (seq.size() == 3)
+            {
+                crlEntryExtensions = X509Extensions.getInstance(seq.getObjectAt(2));
+            }
+        }
+
+        public DERInteger getUserCertificate()
+        {
+            return userCertificate;
+        }
+
+        public Time getRevocationDate()
+        {
+            return revocationDate;
+        }
+
+        public X509Extensions getExtensions()
+        {
+            return crlEntryExtensions;
+        }
+
+        public DERObject toASN1Object()
+        {
+            return seq;
+        }
+    }
+
+    ASN1Sequence     seq;
+
+    DERInteger              version;
+    AlgorithmIdentifier     signature;
+    X509Name                issuer;
+    Time                    thisUpdate;
+    Time                    nextUpdate;
+    CRLEntry[]              revokedCertificates;
+    X509Extensions          crlExtensions;
+
+    public static TBSCertList getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static TBSCertList getInstance(
+        Object  obj)
+    {
+        if (obj instanceof TBSCertList)
+        {
+            return (TBSCertList)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new TBSCertList((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public TBSCertList(
+        ASN1Sequence  seq)
+    {
+        if (seq.size() < 3 || seq.size() > 7)
+        {
+            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+        }
+
+        int seqPos = 0;
+
+        this.seq = seq;
+
+        if (seq.getObjectAt(seqPos) instanceof DERInteger)
+        {
+            version = DERInteger.getInstance(seq.getObjectAt(seqPos++));
+        }
+        else
+        {
+            version = new DERInteger(0);
+        }
+
+        signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqPos++));
+        issuer = X509Name.getInstance(seq.getObjectAt(seqPos++));
+        thisUpdate = Time.getInstance(seq.getObjectAt(seqPos++));
+
+        if (seqPos < seq.size()
+            && (seq.getObjectAt(seqPos) instanceof DERUTCTime
+               || seq.getObjectAt(seqPos) instanceof DERGeneralizedTime
+               || seq.getObjectAt(seqPos) instanceof Time))
+        {
+            nextUpdate = Time.getInstance(seq.getObjectAt(seqPos++));
+        }
+
+        if (seqPos < seq.size()
+            && !(seq.getObjectAt(seqPos) instanceof DERTaggedObject))
+        {
+            ASN1Sequence certs = ASN1Sequence.getInstance(seq.getObjectAt(seqPos++));
+            revokedCertificates = new CRLEntry[certs.size()];
+
+            for (int i = 0; i < revokedCertificates.length; i++)
+            {
+                revokedCertificates[i] = new CRLEntry(ASN1Sequence.getInstance(certs.getObjectAt(i)));
+            }
+        }
+
+        if (seqPos < seq.size()
+            && seq.getObjectAt(seqPos) instanceof DERTaggedObject)
+        {
+            crlExtensions = X509Extensions.getInstance(seq.getObjectAt(seqPos++));
+        }
+    }
+
+    public int getVersion()
+    {
+        return version.getValue().intValue() + 1;
+    }
+
+    public DERInteger getVersionNumber()
+    {
+        return version;
+    }
+
+    public AlgorithmIdentifier getSignature()
+    {
+        return signature;
+    }
+
+    public X509Name getIssuer()
+    {
+        return issuer;
+    }
+
+    public Time getThisUpdate()
+    {
+        return thisUpdate;
+    }
+
+    public Time getNextUpdate()
+    {
+        return nextUpdate;
+    }
+
+    public CRLEntry[] getRevokedCertificates()
+    {
+        return revokedCertificates;
+    }
+
+    public X509Extensions getExtensions()
+    {
+        return crlExtensions;
+    }
+
+    public DERObject toASN1Object()
+    {
+        return seq;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java
new file mode 100644
index 0000000..cc3c0e4
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java
@@ -0,0 +1,193 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+
+/**
+ * The TBSCertificate object.
+ * <pre>
+ * TBSCertificate ::= SEQUENCE {
+ *      version          [ 0 ]  Version DEFAULT v1(0),
+ *      serialNumber            CertificateSerialNumber,
+ *      signature               AlgorithmIdentifier,
+ *      issuer                  Name,
+ *      validity                Validity,
+ *      subject                 Name,
+ *      subjectPublicKeyInfo    SubjectPublicKeyInfo,
+ *      issuerUniqueID    [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ *      subjectUniqueID   [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ *      extensions        [ 3 ] Extensions OPTIONAL
+ *      }
+ * </pre>
+ * <p>
+ * Note: issuerUniqueID and subjectUniqueID are both deprecated by the IETF. This class
+ * will parse them, but you really shouldn't be creating new ones.
+ */
+public class TBSCertificateStructure
+    extends ASN1Encodable
+    implements X509ObjectIdentifiers, PKCSObjectIdentifiers
+{
+    ASN1Sequence            seq;
+
+    DERInteger              version;
+    DERInteger              serialNumber;
+    AlgorithmIdentifier     signature;
+    X509Name                issuer;
+    Time                    startDate, endDate;
+    X509Name                subject;
+    SubjectPublicKeyInfo    subjectPublicKeyInfo;
+    DERBitString            issuerUniqueId;
+    DERBitString            subjectUniqueId;
+    X509Extensions          extensions;
+
+    public static TBSCertificateStructure getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static TBSCertificateStructure getInstance(
+        Object  obj)
+    {
+        if (obj instanceof TBSCertificateStructure)
+        {
+            return (TBSCertificateStructure)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new TBSCertificateStructure((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public TBSCertificateStructure(
+        ASN1Sequence  seq)
+    {
+        int         seqStart = 0;
+
+        this.seq = seq;
+
+        //
+        // some certficates don't include a version number - we assume v1
+        //
+        if (seq.getObjectAt(0) instanceof DERTaggedObject)
+        {
+            version = DERInteger.getInstance(seq.getObjectAt(0));
+        }
+        else
+        {
+            seqStart = -1;          // field 0 is missing!
+            version = new DERInteger(0);
+        }
+
+        serialNumber = DERInteger.getInstance(seq.getObjectAt(seqStart + 1));
+
+        signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqStart + 2));
+        issuer = X509Name.getInstance(seq.getObjectAt(seqStart + 3));
+
+        //
+        // before and after dates
+        //
+        ASN1Sequence  dates = (ASN1Sequence)seq.getObjectAt(seqStart + 4);
+
+        startDate = Time.getInstance(dates.getObjectAt(0));
+        endDate = Time.getInstance(dates.getObjectAt(1));
+
+        subject = X509Name.getInstance(seq.getObjectAt(seqStart + 5));
+
+        //
+        // public key info.
+        //
+        subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(seqStart + 6));
+
+        for (int extras = seq.size() - (seqStart + 6) - 1; extras > 0; extras--)
+        {
+            DERTaggedObject extra = (DERTaggedObject)seq.getObjectAt(seqStart + 6 + extras);
+
+            switch (extra.getTagNo())
+            {
+            case 1:
+                issuerUniqueId = DERBitString.getInstance(extra, false);
+                break;
+            case 2:
+                subjectUniqueId = DERBitString.getInstance(extra, false);
+                break;
+            case 3:
+                extensions = X509Extensions.getInstance(extra);
+            }
+        }
+    }
+
+    public int getVersion()
+    {
+        return version.getValue().intValue() + 1;
+    }
+
+    public DERInteger getVersionNumber()
+    {
+        return version;
+    }
+
+    public DERInteger getSerialNumber()
+    {
+        return serialNumber;
+    }
+
+    public AlgorithmIdentifier getSignature()
+    {
+        return signature;
+    }
+
+    public X509Name getIssuer()
+    {
+        return issuer;
+    }
+
+    public Time getStartDate()
+    {
+        return startDate;
+    }
+
+    public Time getEndDate()
+    {
+        return endDate;
+    }
+
+    public X509Name getSubject()
+    {
+        return subject;
+    }
+
+    public SubjectPublicKeyInfo getSubjectPublicKeyInfo()
+    {
+        return subjectPublicKeyInfo;
+    }
+
+    public DERBitString getIssuerUniqueId()
+    {
+        return issuerUniqueId;
+    }
+
+    public DERBitString getSubjectUniqueId()
+    {
+        return subjectUniqueId;
+    }
+
+    public X509Extensions getExtensions()
+    {
+        return extensions;
+    }
+
+    public DERObject toASN1Object()
+    {
+        return seq;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/Time.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/Time.java
new file mode 100644
index 0000000..7662ee4
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/Time.java
@@ -0,0 +1,116 @@
+package org.bouncycastle.asn1.x509;
+
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.SimpleTimeZone;
+
+import org.bouncycastle.asn1.ASN1Choice;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERGeneralizedTime;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERUTCTime;
+
+public class Time
+    extends ASN1Encodable
+    implements ASN1Choice
+{
+    DERObject   time;
+
+    public static Time getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(obj.getObject()); // must be explicitly tagged
+    }
+
+    public Time(
+        DERObject   time)
+    {
+        if (!(time instanceof DERUTCTime)
+            && !(time instanceof DERGeneralizedTime))
+        {
+            throw new IllegalArgumentException("unknown object passed to Time");
+        }
+
+        this.time = time; 
+    }
+
+    /**
+     * creates a time object from a given date - if the date is between 1950
+     * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime
+     * is used.
+     */
+    public Time(
+        Date    date)
+    {
+        SimpleTimeZone      tz = new SimpleTimeZone(0, "Z");
+        SimpleDateFormat    dateF = new SimpleDateFormat("yyyyMMddHHmmss");
+
+        dateF.setTimeZone(tz);
+
+        String  d = dateF.format(date) + "Z";
+        int     year = Integer.parseInt(d.substring(0, 4));
+
+        if (year < 1950 || year > 2049)
+        {
+            time = new DERGeneralizedTime(d);
+        }
+        else
+        {
+            time = new DERUTCTime(d.substring(2));
+        }
+    }
+
+    public static Time getInstance(
+        Object  obj)
+    {
+        if (obj instanceof Time)
+        {
+            return (Time)obj;
+        }
+        else if (obj instanceof DERUTCTime)
+        {
+            return new Time((DERUTCTime)obj);
+        }
+        else if (obj instanceof DERGeneralizedTime)
+        {
+            return new Time((DERGeneralizedTime)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public String getTime()
+    {
+        if (time instanceof DERUTCTime)
+        {
+            return ((DERUTCTime)time).getAdjustedTime();
+        }
+        else
+        {
+            return ((DERGeneralizedTime)time).getTime();
+        }
+    }
+
+    public Date getDate()
+    {
+        SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
+
+        return dateF.parse(this.getTime(), new ParsePosition(0));
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     * Time ::= CHOICE {
+     *             utcTime        UTCTime,
+     *             generalTime    GeneralizedTime }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        return time;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/UserNotice.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/UserNotice.java
new file mode 100644
index 0000000..b3785ff
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/UserNotice.java
@@ -0,0 +1,117 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+/**
+ * <code>UserNotice</code> class, used in
+ * <code>CertificatePolicies</code> X509 extensions (in policy
+ * qualifiers).
+ * <pre>
+ * UserNotice ::= SEQUENCE {
+ *      noticeRef        NoticeReference OPTIONAL,
+ *      explicitText     DisplayText OPTIONAL}
+ *
+ * </pre>
+ * 
+ * @see PolicyQualifierId
+ * @see PolicyInformation
+ */
+public class UserNotice 
+    extends ASN1Encodable 
+{
+    private NoticeReference noticeRef;
+    private DisplayText     explicitText;
+   
+    /**
+     * Creates a new <code>UserNotice</code> instance.
+     *
+     * @param noticeRef a <code>NoticeReference</code> value
+     * @param explicitText a <code>DisplayText</code> value
+     */
+    public UserNotice(
+        NoticeReference noticeRef, 
+        DisplayText explicitText) 
+    {
+        this.noticeRef = noticeRef;
+        this.explicitText = explicitText;
+    }
+
+    /**
+     * Creates a new <code>UserNotice</code> instance.
+     *
+     * @param noticeRef a <code>NoticeReference</code> value
+     * @param str the explicitText field as a String. 
+     */
+    public UserNotice(
+        NoticeReference noticeRef, 
+        String str) 
+    {
+        this.noticeRef = noticeRef;
+        this.explicitText = new DisplayText(str);
+    }
+
+    /**
+     * Creates a new <code>UserNotice</code> instance.
+     * <p>Useful from reconstructing a <code>UserNotice</code> instance
+     * from its encodable/encoded form. 
+     *
+     * @param as an <code>ASN1Sequence</code> value obtained from either
+     * calling @{link toASN1Object()} for a <code>UserNotice</code>
+     * instance or from parsing it from a DER-encoded stream. 
+     */
+    public UserNotice(
+       ASN1Sequence as) 
+    {
+       if (as.size() == 2)
+       {
+           noticeRef = NoticeReference.getInstance(as.getObjectAt(0));
+           explicitText = DisplayText.getInstance(as.getObjectAt(1));
+       }
+       else if (as.size() == 1)
+       {
+           if (as.getObjectAt(0).getDERObject() instanceof ASN1Sequence)
+           {
+               noticeRef = NoticeReference.getInstance(as.getObjectAt(0));
+           }
+           else
+           {
+               explicitText = DisplayText.getInstance(as.getObjectAt(0));
+           }
+       }
+       else
+       {
+           throw new IllegalArgumentException("Bad sequence size: " + as.size());
+       }
+    }
+   
+    public NoticeReference getNoticeRef()
+    {
+        return noticeRef;
+    }
+    
+    public DisplayText getExplicitText()
+    {
+        return explicitText;
+    }
+    
+    public DERObject toASN1Object() 
+    {
+        ASN1EncodableVector av = new ASN1EncodableVector();
+      
+        if (noticeRef != null)
+        {
+            av.add(noticeRef);
+        }
+        
+        if (explicitText != null)
+        {
+            av.add(explicitText);
+        }
+         
+        return new DERSequence(av);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java
new file mode 100644
index 0000000..53505d1
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java
@@ -0,0 +1,125 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.DERUTCTime;
+
+/**
+ * Generator for Version 1 TBSCertificateStructures.
+ * <pre>
+ * TBSCertificate ::= SEQUENCE {
+ *      version          [ 0 ]  Version DEFAULT v1(0),
+ *      serialNumber            CertificateSerialNumber,
+ *      signature               AlgorithmIdentifier,
+ *      issuer                  Name,
+ *      validity                Validity,
+ *      subject                 Name,
+ *      subjectPublicKeyInfo    SubjectPublicKeyInfo,
+ *      }
+ * </pre>
+ *
+ */
+public class V1TBSCertificateGenerator
+{
+    DERTaggedObject         version = new DERTaggedObject(0, new DERInteger(0));
+
+    DERInteger              serialNumber;
+    AlgorithmIdentifier     signature;
+    X509Name                issuer;
+    Time                    startDate, endDate;
+    X509Name                subject;
+    SubjectPublicKeyInfo    subjectPublicKeyInfo;
+
+    public V1TBSCertificateGenerator()
+    {
+    }
+
+    public void setSerialNumber(
+        DERInteger  serialNumber)
+    {
+        this.serialNumber = serialNumber;
+    }
+
+    public void setSignature(
+        AlgorithmIdentifier    signature)
+    {
+        this.signature = signature;
+    }
+
+    public void setIssuer(
+        X509Name    issuer)
+    {
+        this.issuer = issuer;
+    }
+
+    public void setStartDate(
+        Time startDate)
+    {
+        this.startDate = startDate;
+    }
+
+    public void setStartDate(
+        DERUTCTime startDate)
+    {
+        this.startDate = new Time(startDate);
+    }
+
+    public void setEndDate(
+        Time endDate)
+    {
+        this.endDate = endDate;
+    }
+
+    public void setEndDate(
+        DERUTCTime endDate)
+    {
+        this.endDate = new Time(endDate);
+    }
+
+    public void setSubject(
+        X509Name    subject)
+    {
+        this.subject = subject;
+    }
+
+    public void setSubjectPublicKeyInfo(
+        SubjectPublicKeyInfo    pubKeyInfo)
+    {
+        this.subjectPublicKeyInfo = pubKeyInfo;
+    }
+
+    public TBSCertificateStructure generateTBSCertificate()
+    {
+        if ((serialNumber == null) || (signature == null)
+            || (issuer == null) || (startDate == null) || (endDate == null)
+            || (subject == null) || (subjectPublicKeyInfo == null))
+        {
+            throw new IllegalStateException("not all mandatory fields set in V1 TBScertificate generator");
+        }
+
+        ASN1EncodableVector  seq = new ASN1EncodableVector();
+
+        // seq.add(version); - not required as default value.
+        seq.add(serialNumber);
+        seq.add(signature);
+        seq.add(issuer);
+
+        //
+        // before and after dates
+        //
+        ASN1EncodableVector  validity = new ASN1EncodableVector();
+
+        validity.add(startDate);
+        validity.add(endDate);
+
+        seq.add(new DERSequence(validity));
+
+        seq.add(subject);
+
+        seq.add(subjectPublicKeyInfo);
+
+        return new TBSCertificateStructure(new DERSequence(seq));
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/V2AttributeCertificateInfoGenerator.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/V2AttributeCertificateInfoGenerator.java
new file mode 100644
index 0000000..5931f77
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/V2AttributeCertificateInfoGenerator.java
@@ -0,0 +1,146 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERGeneralizedTime;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERSet;
+
+/**
+ * Generator for Version 2 AttributeCertificateInfo
+ * <pre>
+ * AttributeCertificateInfo ::= SEQUENCE {
+ *       version              AttCertVersion -- version is v2,
+ *       holder               Holder,
+ *       issuer               AttCertIssuer,
+ *       signature            AlgorithmIdentifier,
+ *       serialNumber         CertificateSerialNumber,
+ *       attrCertValidityPeriod   AttCertValidityPeriod,
+ *       attributes           SEQUENCE OF Attribute,
+ *       issuerUniqueID       UniqueIdentifier OPTIONAL,
+ *       extensions           Extensions OPTIONAL
+ * }
+ * </pre>
+ *
+ */
+public class V2AttributeCertificateInfoGenerator
+{
+    private DERInteger version;
+    private Holder holder;
+    private AttCertIssuer issuer;
+    private AlgorithmIdentifier signature;
+    private DERInteger serialNumber;
+    private AttCertValidityPeriod attrCertValidityPeriod;
+    private ASN1EncodableVector attributes;
+    private DERBitString issuerUniqueID;
+    private X509Extensions extensions;
+    private DERGeneralizedTime startDate, endDate;
+
+    public V2AttributeCertificateInfoGenerator()
+    {
+        this.version = new DERInteger(1);
+        attributes = new ASN1EncodableVector();
+    }
+    
+    public void setHolder(Holder holder)
+    {
+        this.holder = holder;
+    }
+    
+    public void addAttribute(String oid, ASN1Encodable value) 
+    {
+        attributes.add(new Attribute(new DERObjectIdentifier(oid), new DERSet(value)));
+    }
+
+    /**
+     * @param attribute
+     */
+    public void addAttribute(Attribute attribute)
+    {
+        attributes.add(attribute);
+    }
+    
+    public void setSerialNumber(
+        DERInteger  serialNumber)
+    {
+        this.serialNumber = serialNumber;
+    }
+
+    public void setSignature(
+        AlgorithmIdentifier    signature)
+    {
+        this.signature = signature;
+    }
+
+    public void setIssuer(
+        AttCertIssuer    issuer)
+    {
+        this.issuer = issuer;
+    }
+
+    public void setStartDate(
+        DERGeneralizedTime startDate)
+    {
+        this.startDate = startDate;
+    }
+
+    public void setEndDate(
+        DERGeneralizedTime endDate)
+    {
+        this.endDate = endDate;
+    }
+
+    public void setIssuerUniqueID(
+        DERBitString    issuerUniqueID)
+    {
+        this.issuerUniqueID = issuerUniqueID;
+    }
+
+    public void setExtensions(
+        X509Extensions    extensions)
+    {
+        this.extensions = extensions;
+    }
+
+    public AttributeCertificateInfo generateAttributeCertificateInfo()
+    {
+        if ((serialNumber == null) || (signature == null)
+            || (issuer == null) || (startDate == null) || (endDate == null)
+            || (holder == null) || (attributes == null))
+        {
+            throw new IllegalStateException("not all mandatory fields set in V2 AttributeCertificateInfo generator");
+        }
+
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(version);
+        v.add(holder);
+        v.add(issuer);
+        v.add(signature);
+        v.add(serialNumber);
+    
+        //
+        // before and after dates => AttCertValidityPeriod
+        //
+        AttCertValidityPeriod validity = new AttCertValidityPeriod(startDate, endDate);
+        v.add(validity);
+        
+        // Attributes
+        v.add(new DERSequence(attributes));
+        
+        if (issuerUniqueID != null)
+        {
+            v.add(issuerUniqueID);
+        }
+    
+        if (extensions != null)
+        {
+            v.add(extensions);
+        }
+
+        return new AttributeCertificateInfo(new DERSequence(v));
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/V2Form.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/V2Form.java
new file mode 100644
index 0000000..6a229dd
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/V2Form.java
@@ -0,0 +1,130 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+public class V2Form
+    extends ASN1Encodable
+{
+    GeneralNames        issuerName;
+    IssuerSerial        baseCertificateID;
+    ObjectDigestInfo    objectDigestInfo;
+
+    public static V2Form getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static V2Form getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof V2Form)
+        {
+            return (V2Form)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new V2Form((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+    
+    public V2Form(
+        GeneralNames    issuerName)
+    {
+        this.issuerName = issuerName;
+    }
+    
+    public V2Form(
+        ASN1Sequence seq)
+    {
+        if (seq.size() > 3)
+        {
+            throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+        }
+        
+        int    index = 0;
+
+        if (!(seq.getObjectAt(0) instanceof ASN1TaggedObject))
+        {
+            index++;
+            this.issuerName = GeneralNames.getInstance(seq.getObjectAt(0));
+        }
+
+        for (int i = index; i != seq.size(); i++)
+        {
+            ASN1TaggedObject o = ASN1TaggedObject.getInstance(seq.getObjectAt(i));
+            if (o.getTagNo() == 0)
+            {
+                baseCertificateID = IssuerSerial.getInstance(o, false);
+            }
+            else if (o.getTagNo() == 1)
+            {
+                objectDigestInfo = ObjectDigestInfo.getInstance(o, false);
+            }
+            else 
+            {
+                throw new IllegalArgumentException("Bad tag number: "
+                        + o.getTagNo());
+            }
+        }
+    }
+    
+    public GeneralNames getIssuerName()
+    {
+        return issuerName;
+    }
+
+    public IssuerSerial getBaseCertificateID()
+    {
+        return baseCertificateID;
+    }
+
+    public ObjectDigestInfo getObjectDigestInfo()
+    {
+        return objectDigestInfo;
+    }
+
+    /**
+     * Produce an object suitable for an ASN1OutputStream.
+     * <pre>
+     *  V2Form ::= SEQUENCE {
+     *       issuerName            GeneralNames  OPTIONAL,
+     *       baseCertificateID     [0] IssuerSerial  OPTIONAL,
+     *       objectDigestInfo      [1] ObjectDigestInfo  OPTIONAL
+     *         -- issuerName MUST be present in this profile
+     *         -- baseCertificateID and objectDigestInfo MUST NOT
+     *         -- be present in this profile
+     *  }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        if (issuerName != null)
+        {
+            v.add(issuerName);
+        }
+
+        if (baseCertificateID != null)
+        {
+            v.add(new DERTaggedObject(false, 0, baseCertificateID));
+        }
+
+        if (objectDigestInfo != null)
+        {
+            v.add(new DERTaggedObject(false, 1, objectDigestInfo));
+        }
+
+        return new DERSequence(v);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/V2TBSCertListGenerator.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/V2TBSCertListGenerator.java
new file mode 100644
index 0000000..f50a3b8
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/V2TBSCertListGenerator.java
@@ -0,0 +1,213 @@
+package org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERGeneralizedTime;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.DERUTCTime;
+
+/**
+ * Generator for Version 2 TBSCertList structures.
+ * <pre>
+ *  TBSCertList  ::=  SEQUENCE  {
+ *       version                 Version OPTIONAL,
+ *                                    -- if present, shall be v2
+ *       signature               AlgorithmIdentifier,
+ *       issuer                  Name,
+ *       thisUpdate              Time,
+ *       nextUpdate              Time OPTIONAL,
+ *       revokedCertificates     SEQUENCE OF SEQUENCE  {
+ *            userCertificate         CertificateSerialNumber,
+ *            revocationDate          Time,
+ *            crlEntryExtensions      Extensions OPTIONAL
+ *                                          -- if present, shall be v2
+ *                                 }  OPTIONAL,
+ *       crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
+ *                                          -- if present, shall be v2
+ *                                 }
+ * </pre>
+ *
+ * <b>Note: This class may be subject to change</b>
+ */
+public class V2TBSCertListGenerator
+{
+    DERInteger version = new DERInteger(1);
+
+    AlgorithmIdentifier     signature;
+    X509Name                issuer;
+    Time                    thisUpdate, nextUpdate=null;
+    X509Extensions          extensions=null;
+    private Vector          crlentries=null;
+
+    public V2TBSCertListGenerator()
+    {
+    }
+
+
+    public void setSignature(
+        AlgorithmIdentifier    signature)
+    {
+        this.signature = signature;
+    }
+
+    public void setIssuer(
+        X509Name    issuer)
+    {
+        this.issuer = issuer;
+    }
+
+    public void setThisUpdate(
+        DERUTCTime thisUpdate)
+    {
+        this.thisUpdate = new Time(thisUpdate);
+    }
+
+    public void setNextUpdate(
+        DERUTCTime nextUpdate)
+    {
+        this.nextUpdate = new Time(nextUpdate);
+    }
+
+    public void setThisUpdate(
+        Time thisUpdate)
+    {
+        this.thisUpdate = thisUpdate;
+    }
+
+    public void setNextUpdate(
+        Time nextUpdate)
+    {
+        this.nextUpdate = nextUpdate;
+    }
+
+    public void addCRLEntry(
+        ASN1Sequence crlEntry)
+    {
+        if (crlentries == null)
+        {
+            crlentries = new Vector();
+        }
+        
+        crlentries.addElement(crlEntry);
+    }
+
+    public void addCRLEntry(DERInteger userCertificate, DERUTCTime revocationDate, int reason)
+    {
+        addCRLEntry(userCertificate, new Time(revocationDate), reason);
+    }
+
+    public void addCRLEntry(DERInteger userCertificate, Time revocationDate, int reason)
+    {
+        addCRLEntry(userCertificate, revocationDate, reason, null);
+    }
+
+    public void addCRLEntry(DERInteger userCertificate, Time revocationDate, int reason, DERGeneralizedTime invalidityDate)
+    {
+        Vector extOids = new Vector();
+        Vector extValues = new Vector();
+        
+        if (reason != 0)
+        {
+            CRLReason crlReason = new CRLReason(reason);
+            
+            try
+            {
+                extOids.addElement(X509Extensions.ReasonCode);
+                extValues.addElement(new X509Extension(false, new DEROctetString(crlReason.getEncoded())));
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("error encoding reason: " + e);
+            }
+        }
+
+        if (invalidityDate != null)
+        {
+            try
+            {
+                extOids.addElement(X509Extensions.InvalidityDate);
+                extValues.addElement(new X509Extension(false, new DEROctetString(invalidityDate.getEncoded())));
+            }
+            catch (IOException e)
+            {
+                throw new IllegalArgumentException("error encoding invalidityDate: " + e);
+            }
+        }
+        
+        if (extOids.size() != 0)
+        {
+            addCRLEntry(userCertificate, revocationDate, new X509Extensions(extOids, extValues));
+        }
+        else
+        {
+            addCRLEntry(userCertificate, revocationDate, null);
+        }
+    }
+
+    public void addCRLEntry(DERInteger userCertificate, Time revocationDate, X509Extensions extensions)
+    {
+        ASN1EncodableVector v = new ASN1EncodableVector();
+
+        v.add(userCertificate);
+        v.add(revocationDate);
+        
+        if (extensions != null)
+        {
+            v.add(extensions);
+        }
+        
+        addCRLEntry(new DERSequence(v));
+    }
+    
+    public void setExtensions(
+        X509Extensions    extensions)
+    {
+        this.extensions = extensions;
+    }
+
+    public TBSCertList generateTBSCertList()
+    {
+        if ((signature == null) || (issuer == null) || (thisUpdate == null))
+        {
+            throw new IllegalStateException("Not all mandatory fields set in V2 TBSCertList generator.");
+        }
+
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(version);
+        v.add(signature);
+        v.add(issuer);
+
+        v.add(thisUpdate);
+        if (nextUpdate != null)
+        {
+            v.add(nextUpdate);
+        }
+
+        // Add CRLEntries if they exist
+        if (crlentries != null)
+        {
+            ASN1EncodableVector certs = new ASN1EncodableVector();
+            Enumeration it = crlentries.elements();
+            while(it.hasMoreElements())
+            {
+                certs.add((ASN1Sequence)it.nextElement());
+            }
+            v.add(new DERSequence(certs));
+        }
+
+        if (extensions != null)
+        {
+            v.add(new DERTaggedObject(0, extensions));
+        }
+
+        return new TBSCertList(new DERSequence(v));
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java
new file mode 100644
index 0000000..149d680
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java
@@ -0,0 +1,140 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.DERUTCTime;
+
+/**
+ * Generator for Version 3 TBSCertificateStructures.
+ * <pre>
+ * TBSCertificate ::= SEQUENCE {
+ *      version          [ 0 ]  Version DEFAULT v1(0),
+ *      serialNumber            CertificateSerialNumber,
+ *      signature               AlgorithmIdentifier,
+ *      issuer                  Name,
+ *      validity                Validity,
+ *      subject                 Name,
+ *      subjectPublicKeyInfo    SubjectPublicKeyInfo,
+ *      issuerUniqueID    [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ *      subjectUniqueID   [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ *      extensions        [ 3 ] Extensions OPTIONAL
+ *      }
+ * </pre>
+ *
+ */
+public class V3TBSCertificateGenerator
+{
+    DERTaggedObject         version = new DERTaggedObject(0, new DERInteger(2));
+
+    DERInteger              serialNumber;
+    AlgorithmIdentifier     signature;
+    X509Name                issuer;
+    Time                    startDate, endDate;
+    X509Name                subject;
+    SubjectPublicKeyInfo    subjectPublicKeyInfo;
+    X509Extensions          extensions;
+
+    public V3TBSCertificateGenerator()
+    {
+    }
+
+    public void setSerialNumber(
+        DERInteger  serialNumber)
+    {
+        this.serialNumber = serialNumber;
+    }
+
+    public void setSignature(
+        AlgorithmIdentifier    signature)
+    {
+        this.signature = signature;
+    }
+
+    public void setIssuer(
+        X509Name    issuer)
+    {
+        this.issuer = issuer;
+    }
+
+    public void setStartDate(
+        DERUTCTime startDate)
+    {
+        this.startDate = new Time(startDate);
+    }
+
+    public void setStartDate(
+        Time startDate)
+    {
+        this.startDate = startDate;
+    }
+
+    public void setEndDate(
+        DERUTCTime endDate)
+    {
+        this.endDate = new Time(endDate);
+    }
+
+    public void setEndDate(
+        Time endDate)
+    {
+        this.endDate = endDate;
+    }
+
+    public void setSubject(
+        X509Name    subject)
+    {
+        this.subject = subject;
+    }
+
+    public void setSubjectPublicKeyInfo(
+        SubjectPublicKeyInfo    pubKeyInfo)
+    {
+        this.subjectPublicKeyInfo = pubKeyInfo;
+    }
+
+    public void setExtensions(
+        X509Extensions    extensions)
+    {
+        this.extensions = extensions;
+    }
+
+    public TBSCertificateStructure generateTBSCertificate()
+    {
+        if ((serialNumber == null) || (signature == null)
+            || (issuer == null) || (startDate == null) || (endDate == null)
+            || (subject == null) || (subjectPublicKeyInfo == null))
+        {
+            throw new IllegalStateException("not all mandatory fields set in V3 TBScertificate generator");
+        }
+
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(version);
+        v.add(serialNumber);
+        v.add(signature);
+        v.add(issuer);
+
+        //
+        // before and after dates
+        //
+        ASN1EncodableVector  validity = new ASN1EncodableVector();
+
+        validity.add(startDate);
+        validity.add(endDate);
+
+        v.add(new DERSequence(validity));
+
+        v.add(subject);
+
+        v.add(subjectPublicKeyInfo);
+
+        if (extensions != null)
+        {
+            v.add(new DERTaggedObject(3, extensions));
+        }
+
+        return new TBSCertificateStructure(new DERSequence(v));
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509Attributes.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509Attributes.java
new file mode 100644
index 0000000..8ea18fa
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509Attributes.java
@@ -0,0 +1,8 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+public class X509Attributes
+{
+    public static final DERObjectIdentifier RoleSyntax = new DERObjectIdentifier("2.5.4.72");
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509CertificateStructure.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509CertificateStructure.java
new file mode 100644
index 0000000..599db32
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509CertificateStructure.java
@@ -0,0 +1,127 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+
+/**
+ * an X509Certificate structure.
+ * <pre>
+ *  Certificate ::= SEQUENCE {
+ *      tbsCertificate          TBSCertificate,
+ *      signatureAlgorithm      AlgorithmIdentifier,
+ *      signature               BIT STRING
+ *  }
+ * </pre>
+ */
+public class X509CertificateStructure
+    extends ASN1Encodable
+    implements X509ObjectIdentifiers, PKCSObjectIdentifiers
+{
+    ASN1Sequence  seq;
+    TBSCertificateStructure tbsCert;
+    AlgorithmIdentifier     sigAlgId;
+    DERBitString            sig;
+
+    public static X509CertificateStructure getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static X509CertificateStructure getInstance(
+        Object  obj)
+    {
+        if (obj instanceof X509CertificateStructure)
+        {
+            return (X509CertificateStructure)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new X509CertificateStructure((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory");
+    }
+
+    public X509CertificateStructure(
+        ASN1Sequence  seq)
+    {
+        this.seq = seq;
+
+        //
+        // correct x509 certficate
+        //
+        if (seq.size() == 3)
+        {
+            tbsCert = TBSCertificateStructure.getInstance(seq.getObjectAt(0));
+            sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
+
+            sig = DERBitString.getInstance(seq.getObjectAt(2));
+        }
+        else
+        {
+            throw new IllegalArgumentException("sequence wrong size for a certificate");
+        }
+    }
+
+    public TBSCertificateStructure getTBSCertificate()
+    {
+        return tbsCert;
+    }
+
+    public int getVersion()
+    {
+        return tbsCert.getVersion();
+    }
+
+    public DERInteger getSerialNumber()
+    {
+        return tbsCert.getSerialNumber();
+    }
+
+    public X509Name getIssuer()
+    {
+        return tbsCert.getIssuer();
+    }
+
+    public Time getStartDate()
+    {
+        return tbsCert.getStartDate();
+    }
+
+    public Time getEndDate()
+    {
+        return tbsCert.getEndDate();
+    }
+
+    public X509Name getSubject()
+    {
+        return tbsCert.getSubject();
+    }
+
+    public SubjectPublicKeyInfo getSubjectPublicKeyInfo()
+    {
+        return tbsCert.getSubjectPublicKeyInfo();
+    }
+
+    public AlgorithmIdentifier getSignatureAlgorithm()
+    {
+        return sigAlgId;
+    }
+
+    public DERBitString getSignature()
+    {
+        return sig;
+    }
+
+    public DERObject toASN1Object()
+    {
+        return seq;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509DefaultEntryConverter.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509DefaultEntryConverter.java
new file mode 100644
index 0000000..a9402b6
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509DefaultEntryConverter.java
@@ -0,0 +1,52 @@
+package org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+
+import org.bouncycastle.asn1.DERGeneralizedTime;
+import org.bouncycastle.asn1.DERIA5String;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERUTF8String;
+
+/**
+ * The default converter for X509 DN entries when going from their
+ * string value to ASN.1 strings.
+ */
+public class X509DefaultEntryConverter
+    extends X509NameEntryConverter
+{
+    /**
+     * Apply default coversion for the given value depending on the oid
+     * and the character range of the value.
+     * 
+     * @param oid the object identifier for the DN entry
+     * @param value the value associated with it
+     * @return the ASN.1 equivalent for the string value.
+     */
+    public DERObject getConvertedValue(
+        DERObjectIdentifier  oid,
+        String               value)
+    {
+        if (value.length() != 0 && value.charAt(0) == '#')
+        {
+            try
+            {
+                return convertHexEncoded(value, 1);
+            }
+            catch (IOException e)
+            {
+                throw new RuntimeException("can't recode value for oid " + oid.getId());
+            }
+        }
+        else if (oid.equals(X509Name.EmailAddress) || oid.equals(X509Name.DC))
+        {
+            return new DERIA5String(value);
+        }
+        else if (oid.equals(X509Name.DATE_OF_BIRTH))
+        {
+            return new DERGeneralizedTime(value);
+        }
+        
+        return new DERUTF8String(value);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java
new file mode 100644
index 0000000..19ff3f3
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java
@@ -0,0 +1,64 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.DERBoolean;
+
+/**
+ * an object for the elements in the X.509 V3 extension block.
+ */
+public class X509Extension
+{
+    boolean             critical;
+    ASN1OctetString      value;
+
+    public X509Extension(
+        DERBoolean              critical,
+        ASN1OctetString         value)
+    {
+        this.critical = critical.isTrue();
+        this.value = value;
+    }
+
+    public X509Extension(
+        boolean                 critical,
+        ASN1OctetString         value)
+    {
+        this.critical = critical;
+        this.value = value;
+    }
+
+    public boolean isCritical()
+    {
+        return critical;
+    }
+
+    public ASN1OctetString getValue()
+    {
+        return value;
+    }
+
+    public int hashCode()
+    {
+        if (this.isCritical())
+        {
+            return this.getValue().hashCode();
+        }
+
+        
+        return ~this.getValue().hashCode();
+    }
+
+    public boolean equals(
+        Object  o)
+    {
+        if (!(o instanceof X509Extension))
+        {
+            return false;
+        }
+
+        X509Extension   other = (X509Extension)o;
+
+        return other.getValue().equals(this.getValue())
+            && (other.isCritical() == this.isCritical());
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java
new file mode 100644
index 0000000..be1409b
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java
@@ -0,0 +1,403 @@
+package org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERBoolean;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+// BEGIN android-added
+import org.bouncycastle.asn1.OrderedTable;
+// END android-added
+
+public class X509Extensions
+    extends ASN1Encodable
+{
+    /**
+     * Subject Directory Attributes
+     */
+    public static final DERObjectIdentifier SubjectDirectoryAttributes = new DERObjectIdentifier("2.5.29.9");
+    
+    /**
+     * Subject Key Identifier 
+     */
+    public static final DERObjectIdentifier SubjectKeyIdentifier = new DERObjectIdentifier("2.5.29.14");
+
+    /**
+     * Key Usage 
+     */
+    public static final DERObjectIdentifier KeyUsage = new DERObjectIdentifier("2.5.29.15");
+
+    /**
+     * Private Key Usage Period 
+     */
+    public static final DERObjectIdentifier PrivateKeyUsagePeriod = new DERObjectIdentifier("2.5.29.16");
+
+    /**
+     * Subject Alternative Name 
+     */
+    public static final DERObjectIdentifier SubjectAlternativeName = new DERObjectIdentifier("2.5.29.17");
+
+    /**
+     * Issuer Alternative Name 
+     */
+    public static final DERObjectIdentifier IssuerAlternativeName = new DERObjectIdentifier("2.5.29.18");
+
+    /**
+     * Basic Constraints 
+     */
+    public static final DERObjectIdentifier BasicConstraints = new DERObjectIdentifier("2.5.29.19");
+
+    /**
+     * CRL Number 
+     */
+    public static final DERObjectIdentifier CRLNumber = new DERObjectIdentifier("2.5.29.20");
+
+    /**
+     * Reason code 
+     */
+    public static final DERObjectIdentifier ReasonCode = new DERObjectIdentifier("2.5.29.21");
+
+    /**
+     * Hold Instruction Code 
+     */
+    public static final DERObjectIdentifier InstructionCode = new DERObjectIdentifier("2.5.29.23");
+
+    /**
+     * Invalidity Date 
+     */
+    public static final DERObjectIdentifier InvalidityDate = new DERObjectIdentifier("2.5.29.24");
+
+    /**
+     * Delta CRL indicator 
+     */
+    public static final DERObjectIdentifier DeltaCRLIndicator = new DERObjectIdentifier("2.5.29.27");
+
+    /**
+     * Issuing Distribution Point 
+     */
+    public static final DERObjectIdentifier IssuingDistributionPoint = new DERObjectIdentifier("2.5.29.28");
+
+    /**
+     * Certificate Issuer 
+     */
+    public static final DERObjectIdentifier CertificateIssuer = new DERObjectIdentifier("2.5.29.29");
+
+    /**
+     * Name Constraints 
+     */
+    public static final DERObjectIdentifier NameConstraints = new DERObjectIdentifier("2.5.29.30");
+
+    /**
+     * CRL Distribution Points 
+     */
+    public static final DERObjectIdentifier CRLDistributionPoints = new DERObjectIdentifier("2.5.29.31");
+
+    /**
+     * Certificate Policies 
+     */
+    public static final DERObjectIdentifier CertificatePolicies = new DERObjectIdentifier("2.5.29.32");
+
+    /**
+     * Policy Mappings 
+     */
+    public static final DERObjectIdentifier PolicyMappings = new DERObjectIdentifier("2.5.29.33");
+
+    /**
+     * Authority Key Identifier 
+     */
+    public static final DERObjectIdentifier AuthorityKeyIdentifier = new DERObjectIdentifier("2.5.29.35");
+
+    /**
+     * Policy Constraints 
+     */
+    public static final DERObjectIdentifier PolicyConstraints = new DERObjectIdentifier("2.5.29.36");
+
+    /**
+     * Extended Key Usage 
+     */
+    public static final DERObjectIdentifier ExtendedKeyUsage = new DERObjectIdentifier("2.5.29.37");
+
+    /**
+     * Freshest CRL
+     */
+    public static final DERObjectIdentifier FreshestCRL = new DERObjectIdentifier("2.5.29.46");
+     
+    /**
+     * Inhibit Any Policy
+     */
+    public static final DERObjectIdentifier InhibitAnyPolicy = new DERObjectIdentifier("2.5.29.54");
+
+    /**
+     * Authority Info Access
+     */
+    public static final DERObjectIdentifier AuthorityInfoAccess = new DERObjectIdentifier("1.3.6.1.5.5.7.1.1");
+
+    /**
+     * Subject Info Access
+     */
+    public static final DERObjectIdentifier SubjectInfoAccess = new DERObjectIdentifier("1.3.6.1.5.5.7.1.11");
+    
+    /**
+     * BiometricInfo
+     */
+    public static final DERObjectIdentifier BiometricInfo = new DERObjectIdentifier("1.3.6.1.5.5.7.1.2");
+    
+    /**
+     * QCStatements
+     */
+    public static final DERObjectIdentifier QCStatements = new DERObjectIdentifier("1.3.6.1.5.5.7.1.3");
+
+    // BEGIN android-changed
+    private OrderedTable table = new OrderedTable();
+    // END android-changed
+
+    public static X509Extensions getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static X509Extensions getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof X509Extensions)
+        {
+            return (X509Extensions)obj;
+        }
+
+        if (obj instanceof ASN1Sequence)
+        {
+            return new X509Extensions((ASN1Sequence)obj);
+        }
+
+        if (obj instanceof ASN1TaggedObject)
+        {
+            return getInstance(((ASN1TaggedObject)obj).getObject());
+        }
+
+        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+    }
+
+    /**
+     * Constructor from ASN1Sequence.
+     *
+     * the extensions are a list of constructed sequences, either with (OID, OctetString) or (OID, Boolean, OctetString)
+     */
+    public X509Extensions(
+        ASN1Sequence  seq)
+    {
+        Enumeration e = seq.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            ASN1Sequence            s = ASN1Sequence.getInstance(e.nextElement());
+
+            // BEGIN android-changed
+            int sSize = s.size();
+            DERObjectIdentifier key = (DERObjectIdentifier) s.getObjectAt(0);
+            Object value;
+            
+            if (sSize == 3)
+            {
+                value = new X509Extension(DERBoolean.getInstance(s.getObjectAt(1)), ASN1OctetString.getInstance(s.getObjectAt(2)));
+            }
+            else if (sSize == 2)
+            {
+                value = new X509Extension(false, ASN1OctetString.getInstance(s.getObjectAt(1)));
+            }
+            else
+            {
+                throw new IllegalArgumentException("Bad sequence size: " + sSize);
+            }
+
+            table.add(key, value);
+            // END android-changed
+        }
+    }
+
+    /**
+     * constructor from a table of extensions.
+     * <p>
+     * it's is assumed the table contains OID/String pairs.
+     */
+    public X509Extensions(
+        Hashtable  extensions)
+    {
+        this(null, extensions);
+    }
+
+    /**
+     * Constructor from a table of extensions with ordering.
+     * <p>
+     * It's is assumed the table contains OID/String pairs.
+     */
+    public X509Extensions(
+        Vector      ordering,
+        Hashtable   extensions)
+    {
+        Enumeration e;
+
+        if (ordering == null)
+        {
+            e = extensions.keys();
+        }
+        else
+        {
+            e = ordering.elements();
+        }
+
+        // BEGIN android-changed
+        while (e.hasMoreElements())
+        {
+            DERObjectIdentifier     oid = (DERObjectIdentifier)e.nextElement();
+            X509Extension           ext = (X509Extension)extensions.get(oid);
+            table.add(oid, ext);
+        }
+        // END android-changed
+    }
+
+    /**
+     * Constructor from two vectors
+     * 
+     * @param objectIDs a vector of the object identifiers.
+     * @param values a vector of the extension values.
+     */
+    public X509Extensions(
+        Vector      objectIDs,
+        Vector      values)
+    {
+        Enumeration e = objectIDs.elements();
+
+        // BEGIN android-changed
+        int count = 0;
+        
+        while (e.hasMoreElements())
+        {
+            DERObjectIdentifier     oid = (DERObjectIdentifier)e.nextElement();
+            X509Extension           ext = (X509Extension)values.elementAt(count);
+
+            table.add(oid, ext);
+            count++;
+        }
+        // END android-changed
+    }
+    
+    /**
+     * return an Enumeration of the extension field's object ids.
+     */
+    public Enumeration oids()
+    {
+        // BEGIN android-changed
+        return table.getKeys();
+        // END android-changed
+    }
+
+    /**
+     * return the extension represented by the object identifier
+     * passed in.
+     *
+     * @return the extension if it's present, null otherwise.
+     */
+    public X509Extension getExtension(
+        DERObjectIdentifier oid)
+    {
+        // BEGIN android-changed
+        return (X509Extension)table.get(oid);
+        // END android-changed
+    }
+
+    /**
+     * <pre>
+     *     Extensions        ::=   SEQUENCE SIZE (1..MAX) OF Extension
+     *
+     *     Extension         ::=   SEQUENCE {
+     *        extnId            EXTENSION.&amp;id ({ExtensionSet}),
+     *        critical          BOOLEAN DEFAULT FALSE,
+     *        extnValue         OCTET STRING }
+     * </pre>
+     */
+    public DERObject toASN1Object()
+    {
+        // BEGIN android-changed
+        int                     size = table.size();
+        ASN1EncodableVector     vec = new ASN1EncodableVector();
+
+        for (int i = 0; i < size; i++) {
+            DERObjectIdentifier     oid = table.getKey(i);
+            X509Extension           ext = (X509Extension)table.getValue(i);
+            ASN1EncodableVector     v = new ASN1EncodableVector();
+
+            v.add(oid);
+
+            if (ext.isCritical())
+            {
+                v.add(DERBoolean.TRUE);
+            }
+
+            v.add(ext.getValue());
+
+            vec.add(new DERSequence(v));
+        }
+        // END android-changed
+        
+        return new DERSequence(vec);
+    }
+
+    public int hashCode()
+    {
+        // BEGIN android-changed
+        int             size = table.size();
+        int             hashCode = 0;
+
+        for (int i = 0; i < size; i++) {
+            hashCode ^= table.getKey(i).hashCode();
+            hashCode ^= table.getValue(i).hashCode();
+        }
+        // END android-changed
+
+        return hashCode;
+    }
+
+    public boolean equals(
+        Object o)
+    {
+        if (!(o instanceof X509Extensions))
+        {
+            return false;
+        }
+
+        X509Extensions  other = (X509Extensions)o;
+
+        // BEGIN android-changed
+        Enumeration     e1 = table.getKeys();
+        Enumeration     e2 = other.table.getKeys();
+        // END android-changed
+
+        while (e1.hasMoreElements() && e2.hasMoreElements())
+        {
+            Object  o1 = e1.nextElement();
+            Object  o2 = e2.nextElement();
+            
+            if (!o1.equals(o2))
+            {
+                return false;
+            }
+        }
+
+        if (e1.hasMoreElements() || e2.hasMoreElements())
+        {
+            return false;
+        }
+
+        return true;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509Name.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509Name.java
new file mode 100644
index 0000000..0111962
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509Name.java
@@ -0,0 +1,1158 @@
+package org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.*;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.util.encoders.Hex;
+import org.bouncycastle.util.Strings;
+
+// BEGIN android-note
+// Changes to this class now limit X509Names to 32 components. We have
+// never observed an instance created with more than 10.
+// END android-note
+
+/**
+ * <pre>
+ *     RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+ *
+ *     RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
+ *
+ *     AttributeTypeAndValue ::= SEQUENCE {
+ *                                   type  OBJECT IDENTIFIER,
+ *                                   value ANY }
+ * </pre>
+ */
+public class X509Name
+    extends ASN1Encodable
+{
+    /**
+     * country code - StringType(SIZE(2))
+     */
+    public static final DERObjectIdentifier C = new DERObjectIdentifier("2.5.4.6");
+
+    /**
+     * organization - StringType(SIZE(1..64))
+     */
+    public static final DERObjectIdentifier O = new DERObjectIdentifier("2.5.4.10");
+
+    /**
+     * organizational unit name - StringType(SIZE(1..64))
+     */
+    public static final DERObjectIdentifier OU = new DERObjectIdentifier("2.5.4.11");
+
+    /**
+     * Title
+     */
+    public static final DERObjectIdentifier T = new DERObjectIdentifier("2.5.4.12");
+
+    /**
+     * common name - StringType(SIZE(1..64))
+     */
+    public static final DERObjectIdentifier CN = new DERObjectIdentifier("2.5.4.3");
+
+    /**
+     * device serial number name - StringType(SIZE(1..64))
+     */
+    public static final DERObjectIdentifier SN = new DERObjectIdentifier("2.5.4.5");
+
+    /**
+     * street - StringType(SIZE(1..64))
+     */
+    public static final DERObjectIdentifier STREET = new DERObjectIdentifier("2.5.4.9");
+    
+    /**
+     * device serial number name - StringType(SIZE(1..64))
+     */
+    public static final DERObjectIdentifier SERIALNUMBER = SN;
+
+    /**
+     * locality name - StringType(SIZE(1..64))
+     */
+    public static final DERObjectIdentifier L = new DERObjectIdentifier("2.5.4.7");
+
+    /**
+     * state, or province name - StringType(SIZE(1..64))
+     */
+    public static final DERObjectIdentifier ST = new DERObjectIdentifier("2.5.4.8");
+
+    /**
+     * Naming attributes of type X520name
+     */
+    public static final DERObjectIdentifier SURNAME = new DERObjectIdentifier("2.5.4.4");
+    public static final DERObjectIdentifier GIVENNAME = new DERObjectIdentifier("2.5.4.42");
+    public static final DERObjectIdentifier INITIALS = new DERObjectIdentifier("2.5.4.43");
+    public static final DERObjectIdentifier GENERATION = new DERObjectIdentifier("2.5.4.44");
+    public static final DERObjectIdentifier UNIQUE_IDENTIFIER = new DERObjectIdentifier("2.5.4.45");
+
+    /**
+     * businessCategory - DirectoryString(SIZE(1..128)
+     */
+    public static final DERObjectIdentifier BUSINESS_CATEGORY = new DERObjectIdentifier(
+                    "2.5.4.15");
+
+    /**
+     * postalCode - DirectoryString(SIZE(1..40)
+     */
+    public static final DERObjectIdentifier POSTAL_CODE = new DERObjectIdentifier(
+                    "2.5.4.17");
+    
+    /**
+     * dnQualifier - DirectoryString(SIZE(1..64)
+     */
+    public static final DERObjectIdentifier DN_QUALIFIER = new DERObjectIdentifier(
+                    "2.5.4.46");
+
+    /**
+     * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64)
+     */
+    public static final DERObjectIdentifier PSEUDONYM = new DERObjectIdentifier(
+                    "2.5.4.65");
+
+
+    /**
+     * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z
+     */
+    public static final DERObjectIdentifier DATE_OF_BIRTH = new DERObjectIdentifier(
+                    "1.3.6.1.5.5.7.9.1");
+
+    /**
+     * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128)
+     */
+    public static final DERObjectIdentifier PLACE_OF_BIRTH = new DERObjectIdentifier(
+                    "1.3.6.1.5.5.7.9.2");
+
+    /**
+     * RFC 3039 Gender - PrintableString (SIZE(1)) -- "M", "F", "m" or "f"
+     */
+    public static final DERObjectIdentifier GENDER = new DERObjectIdentifier(
+                    "1.3.6.1.5.5.7.9.3");
+
+    /**
+     * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166
+     * codes only
+     */
+    public static final DERObjectIdentifier COUNTRY_OF_CITIZENSHIP = new DERObjectIdentifier(
+                    "1.3.6.1.5.5.7.9.4");
+
+    /**
+     * RFC 3039 CountryOfResidence - PrintableString (SIZE (2)) -- ISO 3166
+     * codes only
+     */
+    public static final DERObjectIdentifier COUNTRY_OF_RESIDENCE = new DERObjectIdentifier(
+                    "1.3.6.1.5.5.7.9.5");
+
+
+    /**
+     * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64)
+     */
+    public static final DERObjectIdentifier NAME_AT_BIRTH =  new DERObjectIdentifier("1.3.36.8.3.14");
+
+    /**
+     * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF
+     * DirectoryString(SIZE(1..30))
+     */
+    public static final DERObjectIdentifier POSTAL_ADDRESS = new DERObjectIdentifier(
+                    "2.5.4.16");
+
+    /**
+     * Email address (RSA PKCS#9 extension) - IA5String.
+     * <p>Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.
+     */
+    public static final DERObjectIdentifier EmailAddress = PKCSObjectIdentifiers.pkcs_9_at_emailAddress;
+    
+    /**
+     * more from PKCS#9
+     */
+    public static final DERObjectIdentifier UnstructuredName = PKCSObjectIdentifiers.pkcs_9_at_unstructuredName;
+    public static final DERObjectIdentifier UnstructuredAddress = PKCSObjectIdentifiers.pkcs_9_at_unstructuredAddress;
+    
+    /**
+     * email address in Verisign certificates
+     */
+    public static final DERObjectIdentifier E = EmailAddress;
+    
+    /*
+     * others...
+     */
+    public static final DERObjectIdentifier DC = new DERObjectIdentifier("0.9.2342.19200300.100.1.25");
+
+    /**
+     * LDAP User id.
+     */
+    public static final DERObjectIdentifier UID = new DERObjectIdentifier("0.9.2342.19200300.100.1.1");
+
+    /**
+     * look up table translating OID values into their common symbols - this static is scheduled for deletion
+     */
+    public static Hashtable OIDLookUp = new Hashtable();
+
+    /**
+     * determines whether or not strings should be processed and printed
+     * from back to front.
+     */
+    public static boolean DefaultReverse = false;
+
+    /**
+     * default look up table translating OID values into their common symbols following
+     * the convention in RFC 2253 with a few extras
+     */
+    public static Hashtable DefaultSymbols = OIDLookUp;
+
+    /**
+     * look up table translating OID values into their common symbols following the convention in RFC 2253
+     * 
+     */
+    public static Hashtable RFC2253Symbols = new Hashtable();
+
+    /**
+     * look up table translating OID values into their common symbols following the convention in RFC 1779
+     * 
+     */
+    public static Hashtable RFC1779Symbols = new Hashtable();
+
+    /**
+     * look up table translating string values into their OIDS -
+     * this static is scheduled for deletion
+     */
+    public static Hashtable SymbolLookUp = new Hashtable();
+
+    /**
+     * look up table translating common symbols into their OIDS.
+     */
+    public static Hashtable DefaultLookUp = SymbolLookUp;
+
+    // BEGIN android-removed
+    //private static final Boolean TRUE = new Boolean(true); // for J2ME compatibility
+    //private static final Boolean FALSE = new Boolean(false);
+    // END android-removed
+
+    static
+    {
+        DefaultSymbols.put(C, "C");
+        DefaultSymbols.put(O, "O");
+        DefaultSymbols.put(T, "T");
+        DefaultSymbols.put(OU, "OU");
+        DefaultSymbols.put(CN, "CN");
+        DefaultSymbols.put(L, "L");
+        DefaultSymbols.put(ST, "ST");
+        DefaultSymbols.put(SN, "SN");
+        DefaultSymbols.put(EmailAddress, "E");
+        DefaultSymbols.put(DC, "DC");
+        DefaultSymbols.put(UID, "UID");
+        DefaultSymbols.put(STREET, "STREET");
+        DefaultSymbols.put(SURNAME, "SURNAME");
+        DefaultSymbols.put(GIVENNAME, "GIVENNAME");
+        DefaultSymbols.put(INITIALS, "INITIALS");
+        DefaultSymbols.put(GENERATION, "GENERATION");
+        DefaultSymbols.put(UnstructuredAddress, "unstructuredAddress");
+        DefaultSymbols.put(UnstructuredName, "unstructuredName");
+        DefaultSymbols.put(UNIQUE_IDENTIFIER, "UniqueIdentifier");
+        DefaultSymbols.put(DN_QUALIFIER, "DN");
+        DefaultSymbols.put(PSEUDONYM, "Pseudonym");
+        DefaultSymbols.put(POSTAL_ADDRESS, "PostalAddress");
+        DefaultSymbols.put(NAME_AT_BIRTH, "NameAtBirth");
+        DefaultSymbols.put(COUNTRY_OF_CITIZENSHIP, "CountryOfCitizenship");
+        DefaultSymbols.put(COUNTRY_OF_RESIDENCE, "CountryOfResidence");
+        DefaultSymbols.put(GENDER, "Gender");
+        DefaultSymbols.put(PLACE_OF_BIRTH, "PlaceOfBirth");
+        DefaultSymbols.put(DATE_OF_BIRTH, "DateOfBirth");
+        DefaultSymbols.put(POSTAL_CODE, "PostalCode");
+        DefaultSymbols.put(BUSINESS_CATEGORY, "BusinessCategory");
+
+        RFC2253Symbols.put(C, "C");
+        RFC2253Symbols.put(O, "O");
+        RFC2253Symbols.put(OU, "OU");
+        RFC2253Symbols.put(CN, "CN");
+        RFC2253Symbols.put(L, "L");
+        RFC2253Symbols.put(ST, "ST");
+        RFC2253Symbols.put(STREET, "STREET");
+        RFC2253Symbols.put(DC, "DC");
+        RFC2253Symbols.put(UID, "UID");
+
+        RFC1779Symbols.put(C, "C");
+        RFC1779Symbols.put(O, "O");
+        RFC1779Symbols.put(OU, "OU");
+        RFC1779Symbols.put(CN, "CN");
+        RFC1779Symbols.put(L, "L");
+        RFC1779Symbols.put(ST, "ST");
+        RFC1779Symbols.put(STREET, "STREET");
+
+        DefaultLookUp.put("c", C);
+        DefaultLookUp.put("o", O);
+        DefaultLookUp.put("t", T);
+        DefaultLookUp.put("ou", OU);
+        DefaultLookUp.put("cn", CN);
+        DefaultLookUp.put("l", L);
+        DefaultLookUp.put("st", ST);
+        DefaultLookUp.put("sn", SN);
+        DefaultLookUp.put("serialnumber", SN);
+        DefaultLookUp.put("street", STREET);
+        DefaultLookUp.put("emailaddress", E);
+        DefaultLookUp.put("dc", DC);
+        DefaultLookUp.put("e", E);
+        DefaultLookUp.put("uid", UID);
+        DefaultLookUp.put("surname", SURNAME);
+        DefaultLookUp.put("givenname", GIVENNAME);
+        DefaultLookUp.put("initials", INITIALS);
+        DefaultLookUp.put("generation", GENERATION);
+        DefaultLookUp.put("unstructuredaddress", UnstructuredAddress);
+        DefaultLookUp.put("unstructuredname", UnstructuredName);
+        DefaultLookUp.put("uniqueidentifier", UNIQUE_IDENTIFIER);
+        DefaultLookUp.put("dn", DN_QUALIFIER);
+        DefaultLookUp.put("pseudonym", PSEUDONYM);
+        DefaultLookUp.put("postaladdress", POSTAL_ADDRESS);
+        DefaultLookUp.put("nameofbirth", NAME_AT_BIRTH);
+        DefaultLookUp.put("countryofcitizenship", COUNTRY_OF_CITIZENSHIP);
+        DefaultLookUp.put("countryofresidence", COUNTRY_OF_RESIDENCE);
+        DefaultLookUp.put("gender", GENDER);
+        DefaultLookUp.put("placeofbirth", PLACE_OF_BIRTH);
+        DefaultLookUp.put("dateofbirth", DATE_OF_BIRTH);
+        DefaultLookUp.put("postalcode", POSTAL_CODE);
+        DefaultLookUp.put("businesscategory", BUSINESS_CATEGORY);
+    }
+
+    private X509NameEntryConverter  converter = null;
+    // BEGIN android-changed
+    private X509NameElementList     elems = new X509NameElementList();
+    // END android-changed
+    
+    private ASN1Sequence            seq;
+
+    /**
+     * Return a X509Name based on the passed in tagged object.
+     * 
+     * @param obj tag object holding name.
+     * @param explicit true if explicitly tagged false otherwise.
+     * @return the X509Name
+     */
+    public static X509Name getInstance(
+        ASN1TaggedObject obj,
+        boolean          explicit)
+    {
+        return getInstance(ASN1Sequence.getInstance(obj, explicit));
+    }
+
+    public static X509Name getInstance(
+        Object  obj)
+    {
+        if (obj == null || obj instanceof X509Name)
+        {
+            return (X509Name)obj;
+        }
+        else if (obj instanceof ASN1Sequence)
+        {
+            return new X509Name((ASN1Sequence)obj);
+        }
+
+        throw new IllegalArgumentException("unknown object in factory \"" + obj.getClass().getName()+"\"");
+    }
+
+    /**
+     * Constructor from ASN1Sequence
+     *
+     * the principal will be a list of constructed sets, each containing an (OID, String) pair.
+     */
+    public X509Name(
+        ASN1Sequence  seq)
+    {
+        this.seq = seq;
+
+        Enumeration e = seq.getObjects();
+
+        while (e.hasMoreElements())
+        {
+            ASN1Set         set = (ASN1Set)e.nextElement();
+
+            for (int i = 0; i < set.size(); i++) 
+            {
+                   // BEGIN android-changed
+                   ASN1Sequence s = (ASN1Sequence)set.getObjectAt(i);
+                   
+                   DERObjectIdentifier key =
+                       (DERObjectIdentifier) s.getObjectAt(0);
+                   DEREncodable value = s.getObjectAt(1);
+                   String valueStr;
+
+                   if (value instanceof DERString)
+                   {
+                       valueStr = ((DERString)value).getString();
+                   }
+                   else
+                   {
+                       valueStr = "#" + bytesToString(Hex.encode(value.getDERObject().getDEREncoded()));
+                   }
+
+                   /*
+                    * The added flag set to (i != 0), to allow earlier JDK
+                    * compatibility.
+                    */
+                   elems.add(key, valueStr, i != 0);
+                   // END android-changed
+            }
+        }
+    }
+
+    /**
+     * constructor from a table of attributes.
+     * <p>
+     * it's is assumed the table contains OID/String pairs, and the contents
+     * of the table are copied into an internal table as part of the
+     * construction process.
+     * <p>
+     * <b>Note:</b> if the name you are trying to generate should be
+     * following a specific ordering, you should use the constructor
+     * with the ordering specified below.
+     */
+    public X509Name(
+        Hashtable  attributes)
+    {
+        this(null, attributes);
+    }
+
+    /**
+     * Constructor from a table of attributes with ordering.
+     * <p>
+     * it's is assumed the table contains OID/String pairs, and the contents
+     * of the table are copied into an internal table as part of the
+     * construction process. The ordering vector should contain the OIDs
+     * in the order they are meant to be encoded or printed in toString.
+     */
+    public X509Name(
+        Vector      ordering,
+        Hashtable   attributes)
+    {
+        this(ordering, attributes, new X509DefaultEntryConverter());
+    }
+
+    /**
+     * Constructor from a table of attributes with ordering.
+     * <p>
+     * it's is assumed the table contains OID/String pairs, and the contents
+     * of the table are copied into an internal table as part of the
+     * construction process. The ordering vector should contain the OIDs
+     * in the order they are meant to be encoded or printed in toString.
+     * <p>
+     * The passed in converter will be used to convert the strings into their
+     * ASN.1 counterparts.
+     */
+    public X509Name(
+        Vector                      ordering,
+        Hashtable                   attributes,
+        X509DefaultEntryConverter   converter)
+    {
+        // BEGIN android-changed
+        DERObjectIdentifier problem = null;
+        this.converter = converter;
+
+        if (ordering != null)
+        {
+            for (int i = 0; i != ordering.size(); i++)
+            {
+                DERObjectIdentifier key =
+                    (DERObjectIdentifier) ordering.elementAt(i);
+                String value = (String) attributes.get(key);
+                if (value == null)
+                {
+                    problem = key;
+                    break;
+                }
+                elems.add(key, value);
+            }
+        }
+        else
+        {
+            Enumeration     e = attributes.keys();
+
+            while (e.hasMoreElements())
+            {
+                DERObjectIdentifier key =
+                    (DERObjectIdentifier) e.nextElement();
+                String value = (String) attributes.get(key);
+                if (value == null)
+                {
+                    problem = key;
+                    break;
+                }
+                elems.add(key, value);
+            }
+        }
+
+        if (problem != null)
+        {
+            throw new IllegalArgumentException("No attribute for object id - " + problem.getId() + " - passed to distinguished name");
+        }
+        // END android-changed
+    }
+
+    /**
+     * Takes two vectors one of the oids and the other of the values.
+     */
+    public X509Name(
+        Vector  oids,
+        Vector  values)
+    {
+        this(oids, values, new X509DefaultEntryConverter());
+    }
+
+    /**
+     * Takes two vectors one of the oids and the other of the values.
+     * <p>
+     * The passed in converter will be used to convert the strings into their
+     * ASN.1 counterparts.
+     */
+    public X509Name(
+        Vector                  oids,
+        Vector                  values,
+        X509NameEntryConverter  converter)
+    {
+        this.converter = converter;
+
+        if (oids.size() != values.size())
+        {
+            throw new IllegalArgumentException("oids vector must be same length as values.");
+        }
+
+        for (int i = 0; i < oids.size(); i++)
+        {
+            // BEGIN android-changed
+            elems.add((DERObjectIdentifier) oids.elementAt(i),
+                    (String) values.elementAt(i));
+            // END android-changed
+        }
+    }
+
+    /**
+     * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+     * some such, converting it into an ordered set of name attributes.
+     */
+    public X509Name(
+        String  dirName)
+    {
+        this(DefaultReverse, DefaultLookUp, dirName);
+    }
+
+    /**
+     * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+     * some such, converting it into an ordered set of name attributes with each
+     * string value being converted to its associated ASN.1 type using the passed
+     * in converter.
+     */
+    public X509Name(
+        String                  dirName,
+        X509NameEntryConverter  converter)
+    {
+        this(DefaultReverse, DefaultLookUp, dirName, converter);
+    }
+
+    /**
+     * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+     * some such, converting it into an ordered set of name attributes. If reverse
+     * is true, create the encoded version of the sequence starting from the
+     * last element in the string.
+     */
+    public X509Name(
+        boolean reverse,
+        String  dirName)
+    {
+        this(reverse, DefaultLookUp, dirName);
+    }
+
+    /**
+     * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+     * some such, converting it into an ordered set of name attributes with each
+     * string value being converted to its associated ASN.1 type using the passed
+     * in converter. If reverse is true the ASN.1 sequence representing the DN will
+     * be built by starting at the end of the string, rather than the start.
+     */
+    public X509Name(
+        boolean                 reverse,
+        String                  dirName,
+        X509NameEntryConverter  converter)
+    {
+        this(reverse, DefaultLookUp, dirName, converter);
+    }
+
+    /**
+     * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+     * some such, converting it into an ordered set of name attributes. lookUp
+     * should provide a table of lookups, indexed by lowercase only strings and
+     * yielding a DERObjectIdentifier, other than that OID. and numeric oids
+     * will be processed automatically.
+     * <br>
+     * If reverse is true, create the encoded version of the sequence
+     * starting from the last element in the string.
+     * @param reverse true if we should start scanning from the end (RFC 2553).
+     * @param lookUp table of names and their oids.
+     * @param dirName the X.500 string to be parsed.
+     */
+    public X509Name(
+        boolean     reverse,
+        Hashtable   lookUp,
+        String      dirName)
+    {
+        this(reverse, lookUp, dirName, new X509DefaultEntryConverter());
+    }
+
+    private DERObjectIdentifier decodeOID(
+        String      name,
+        Hashtable   lookUp)
+    {
+        if (Strings.toUpperCase(name).startsWith("OID."))
+        {
+            return new DERObjectIdentifier(name.substring(4));
+        }
+        else if (name.charAt(0) >= '0' && name.charAt(0) <= '9')
+        {
+            return new DERObjectIdentifier(name);
+        }
+
+        DERObjectIdentifier oid = (DERObjectIdentifier)lookUp.get(Strings.toLowerCase(name));
+        if (oid == null)
+        {
+            throw new IllegalArgumentException("Unknown object id - " + name + " - passed to distinguished name");
+        }
+
+        return oid;
+    }
+
+    /**
+     * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+     * some such, converting it into an ordered set of name attributes. lookUp
+     * should provide a table of lookups, indexed by lowercase only strings and
+     * yielding a DERObjectIdentifier, other than that OID. and numeric oids
+     * will be processed automatically. The passed in converter is used to convert the
+     * string values to the right of each equals sign to their ASN.1 counterparts.
+     * <br>
+     * @param reverse true if we should start scanning from the end, false otherwise.
+     * @param lookUp table of names and oids.
+     * @param dirName the string dirName
+     * @param converter the converter to convert string values into their ASN.1 equivalents
+     */
+    public X509Name(
+        boolean                 reverse,
+        Hashtable               lookUp,
+        String                  dirName,
+        X509NameEntryConverter  converter)
+    {
+        this.converter = converter;
+        X509NameTokenizer   nTok = new X509NameTokenizer(dirName);
+
+        while (nTok.hasMoreTokens())
+        {
+            String  token = nTok.nextToken();
+            int     index = token.indexOf('=');
+
+            if (index == -1)
+            {
+                throw new IllegalArgumentException("badly formated directory string");
+            }
+
+            String              name = token.substring(0, index);
+            String              value = token.substring(index + 1);
+            DERObjectIdentifier oid = decodeOID(name, lookUp);
+
+            if (value.indexOf('+') > 0)
+            {
+                X509NameTokenizer   vTok = new X509NameTokenizer(value, '+');
+
+                // BEGIN android-changed
+                elems.add(oid, vTok.nextToken());
+                // END android-changed
+
+                while (vTok.hasMoreTokens())
+                {
+                    String  sv = vTok.nextToken();
+                    int     ndx = sv.indexOf('=');
+
+                    String  nm = sv.substring(0, ndx);
+                    String  vl = sv.substring(ndx + 1);
+                    // BEGIN android-changed
+                    elems.add(decodeOID(nm, lookUp), vl, true);
+                    // END android-changed
+                }
+            }
+            else
+            {
+                // BEGIN android-changed
+                elems.add(oid, value);
+                // END android-changed
+            }
+        }
+
+        if (reverse)
+        {
+            // BEGIN android-changed
+            elems = elems.reverse();
+            // END android-changed
+        }
+    }
+
+    /**
+     * return a vector of the oids in the name, in the order they were found.
+     */
+    public Vector getOIDs()
+    {
+        // BEGIN android-changed
+        Vector  v = new Vector();
+        int     size = elems.size();
+
+        for (int i = 0; i < size; i++)
+        {
+            v.addElement(elems.getKey(i));
+        }
+
+        return v;
+        // END android-changed
+    }
+
+    /**
+     * return a vector of the values found in the name, in the order they
+     * were found.
+     */
+    public Vector getValues()
+    {
+        // BEGIN android-changed
+        Vector  v = new Vector();
+        int     size = elems.size();
+
+        for (int i = 0; i < size; i++)
+        {
+            v.addElement(elems.getValue(i));
+        }
+
+        return v;
+        // END android-changed
+    }
+
+    public DERObject toASN1Object()
+    {
+        if (seq == null)
+        {
+            // BEGIN android-changed
+            ASN1EncodableVector  vec = new ASN1EncodableVector();
+            ASN1EncodableVector  sVec = new ASN1EncodableVector();
+            DERObjectIdentifier  lstOid = null;
+            int                  size = elems.size();
+            
+            for (int i = 0; i != size; i++)
+            {
+                ASN1EncodableVector     v = new ASN1EncodableVector();
+                DERObjectIdentifier     oid = elems.getKey(i);
+
+                v.add(oid);
+
+                String  str = elems.getValue(i);
+
+                v.add(converter.getConvertedValue(oid, str));
+
+                if (lstOid == null || elems.getAdded(i))
+                {
+                    sVec.add(new DERSequence(v));
+                }
+                else
+                {
+                    vec.add(new DERSet(sVec));
+                    sVec = new ASN1EncodableVector();
+                    
+                    sVec.add(new DERSequence(v));
+                }
+                
+                lstOid = oid;
+            }
+            
+            vec.add(new DERSet(sVec));
+            
+            seq = new DERSequence(vec);
+            // END android-changed
+        }
+
+        return seq;
+    }
+
+    /**
+     * @param inOrder if true the order of both X509 names must be the same,
+     * as well as the values associated with each element.
+     */
+    public boolean equals(Object _obj, boolean inOrder) 
+    {
+        if (_obj == this)
+        {
+            return true;
+        }
+
+        if (!inOrder)
+        {
+            return this.equals(_obj);
+        }
+
+        if (!(_obj instanceof X509Name))
+        {
+            return false;
+        }
+        
+        X509Name _oxn          = (X509Name)_obj;
+        // BEGIN android-changed
+        int      _orderingSize = elems.size();
+
+        if (_orderingSize != _oxn.elems.size()) 
+        {
+            return false;
+        }
+        // END android-changed
+        
+        for(int i = 0; i < _orderingSize; i++) 
+        {
+            // BEGIN android-changed
+            String  _oid   = elems.getKey(i).getId();
+            String  _val   = elems.getValue(i);
+            
+            String _oOID = _oxn.elems.getKey(i).getId();
+            String _oVal = _oxn.elems.getValue(i);
+            // BEGIN android-changed
+
+            if (_oid.equals(_oOID))
+            {
+                _val = Strings.toLowerCase(_val.trim());
+                _oVal = Strings.toLowerCase(_oVal.trim());
+                if (_val.equals(_oVal))
+                {
+                    continue;
+                }
+                else
+                {
+                    StringBuffer    v1 = new StringBuffer();
+                    StringBuffer    v2 = new StringBuffer();
+
+                    if (_val.length() != 0)
+                    {
+                        char    c1 = _val.charAt(0);
+
+                        v1.append(c1);
+
+                        for (int k = 1; k < _val.length(); k++)
+                        {
+                            char    c2 = _val.charAt(k);
+                            if (!(c1 == ' ' && c2 == ' '))
+                            {
+                                v1.append(c2);
+                            }
+                            c1 = c2;
+                        }
+                    }
+
+                    if (_oVal.length() != 0)
+                    {
+                        char    c1 = _oVal.charAt(0);
+
+                        v2.append(c1);
+
+                        for (int k = 1; k < _oVal.length(); k++)
+                        {
+                            char    c2 = _oVal.charAt(k);
+                            if (!(c1 == ' ' && c2 == ' '))
+                            {
+                                v2.append(c2);
+                            }
+                            c1 = c2;
+                        }
+                    }
+
+                    if (!v1.toString().equals(v2.toString()))
+                    {
+                        return false;
+                    }
+                }
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * test for equality - note: case is ignored.
+     */
+    public boolean equals(Object _obj) 
+    {
+        if (_obj == this)
+        {
+            return true;
+        }
+
+        if (!(_obj instanceof X509Name || _obj instanceof ASN1Sequence))
+        {
+            return false;
+        }
+        
+        DERObject derO = ((DEREncodable)_obj).getDERObject();
+        
+        if (this.getDERObject().equals(derO))
+        {
+            return true;
+        }
+        
+        if (!(_obj instanceof X509Name))
+        {
+            return false;
+        }
+        
+        X509Name _oxn          = (X509Name)_obj;
+
+        // BEGIN android-changed
+        int      _orderingSize = elems.size();
+
+        if (_orderingSize != _oxn.elems.size()) 
+        {
+            return false;
+        }
+        // END android-changed
+        
+        boolean[] _indexes = new boolean[_orderingSize];
+
+        for(int i = 0; i < _orderingSize; i++) 
+        {
+            boolean _found = false;
+            // BEGIN android-changed
+            String  _oid   = elems.getKey(i).getId();
+            String  _val   = elems.getValue(i);
+            // END android-changed
+            
+            for(int j = 0; j < _orderingSize; j++) 
+            {
+                if (_indexes[j])
+                {
+                    continue;
+                }
+
+                // BEGIN android-changed
+                String _oOID = elems.getKey(j).getId();
+                String _oVal = _oxn.elems.getValue(j);
+                // END android-changed
+
+                if (_oid.equals(_oOID))
+                {
+                    _val = Strings.toLowerCase(_val.trim());
+                    _oVal = Strings.toLowerCase(_oVal.trim());
+                    if (_val.equals(_oVal))
+                    {
+                        _indexes[j] = true;
+                        _found      = true;
+                        break;
+                    }
+                    else
+                    {
+                        StringBuffer    v1 = new StringBuffer();
+                        StringBuffer    v2 = new StringBuffer();
+
+                        if (_val.length() != 0)
+                        {
+                            char    c1 = _val.charAt(0);
+
+                            v1.append(c1);
+
+                            for (int k = 1; k < _val.length(); k++)
+                            {
+                                char    c2 = _val.charAt(k);
+                                if (!(c1 == ' ' && c2 == ' '))
+                                {
+                                    v1.append(c2);
+                                }
+                                c1 = c2;
+                            }
+                        }
+
+                        if (_oVal.length() != 0)
+                        {
+                            char    c1 = _oVal.charAt(0);
+
+                            v2.append(c1);
+
+                            for (int k = 1; k < _oVal.length(); k++)
+                            {
+                                char    c2 = _oVal.charAt(k);
+                                if (!(c1 == ' ' && c2 == ' '))
+                                {
+                                    v2.append(c2);
+                                }
+                                c1 = c2;
+                            }
+                        }
+
+                        if (v1.toString().equals(v2.toString()))
+                        {
+                            _indexes[j] = true;
+                            _found      = true;
+                            break;
+                        }
+                    }
+                }
+            }
+
+            if(!_found)
+            {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+    
+    public int hashCode()
+    {
+        ASN1Sequence  seq = (ASN1Sequence)this.getDERObject();
+        Enumeration   e = seq.getObjects();
+        int           hashCode = 0;
+
+        while (e.hasMoreElements())
+        {
+            hashCode ^= e.nextElement().hashCode();
+        }
+
+        return hashCode;
+    }
+
+    private void appendValue(
+        StringBuffer        buf,
+        Hashtable           oidSymbols,
+        DERObjectIdentifier oid,
+        String              value)
+    {
+        String  sym = (String)oidSymbols.get(oid);
+
+        if (sym != null)
+        {
+            buf.append(sym);
+        }
+        else
+        {
+            buf.append(oid.getId());
+        }
+
+        buf.append('=');
+
+        int     index = buf.length();
+
+        buf.append(value);
+
+        int     end = buf.length();
+
+        while (index != end)
+        {
+            if ((buf.charAt(index) == ',')
+               || (buf.charAt(index) == '"')
+               || (buf.charAt(index) == '\\')
+               || (buf.charAt(index) == '+')
+               || (buf.charAt(index) == '<')
+               || (buf.charAt(index) == '>')
+               || (buf.charAt(index) == ';'))
+            {
+                buf.insert(index, "\\");
+                index++;
+                end++;
+            }
+
+            index++;
+        }
+    }
+
+    /**
+     * convert the structure to a string - if reverse is true the
+     * oids and values are listed out starting with the last element
+     * in the sequence (ala RFC 2253), otherwise the string will begin
+     * with the first element of the structure. If no string definition
+     * for the oid is found in oidSymbols the string value of the oid is
+     * added. Two standard symbol tables are provided DefaultSymbols, and
+     * RFC2253Symbols as part of this class.
+     *
+     * @param reverse if true start at the end of the sequence and work back.
+     * @param oidSymbols look up table strings for oids.
+     */
+    public String toString(
+        boolean     reverse,
+        Hashtable   oidSymbols)
+    {
+        StringBuffer            buf = new StringBuffer();
+        boolean                 first = true;
+
+        if (reverse)
+        {
+            // BEGIN android-changed
+            for (int i = elems.size() - 1; i >= 0; i--)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    if (elems.getAdded(i + 1))
+                    {
+                        buf.append('+');
+                    }
+                    else
+                    {
+                        buf.append(',');
+                    }
+                }
+
+                appendValue(buf, oidSymbols, 
+                            elems.getKey(i),
+                            elems.getValue(i));
+            }
+            // END android-changed
+        }
+        else
+        {
+            // BEGIN android-changed
+            for (int i = 0; i < elems.size(); i++)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    if (elems.getAdded(i))
+                    {
+                        buf.append('+');
+                    }
+                    else
+                    {
+                        buf.append(',');
+                    }
+                }
+
+                appendValue(buf, oidSymbols, 
+                            elems.getKey(i),
+                            elems.getValue(i));
+            }
+            // END android-changed
+        }
+
+        return buf.toString();
+    }
+
+    private String bytesToString(
+        byte[] data)
+    {
+        char[]  cs = new char[data.length];
+
+        for (int i = 0; i != cs.length; i++)
+        {
+            cs[i] = (char)(data[i] & 0xff);
+        }
+
+        return new String(cs);
+    }
+    
+    public String toString()
+    {
+        return toString(DefaultReverse, DefaultSymbols);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509NameElementList.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509NameElementList.java
new file mode 100644
index 0000000..752cfeb
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509NameElementList.java
@@ -0,0 +1,221 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+// BEGIN android-note
+// This class was extracted from X509Name as a way to keep the element
+// list in a more controlled fashion. Also, unlike the original code,
+// this class imposes a 32 element limit. We have never observed an
+// instance created with more than 10, so the limit seems reasonable.
+// END android-note
+
+/**
+ * List of elements of an X509 name. Each element has a key, a value, and
+ * an "added" flag.
+ */
+public class X509NameElementList {
+    /** null-ok; key #0 */
+    private DERObjectIdentifier key0;
+    
+    /** null-ok; key #1 */
+    private DERObjectIdentifier key1;
+
+    /** null-ok; key #2 */
+    private DERObjectIdentifier key2;
+
+    /** null-ok; key #3 */
+    private DERObjectIdentifier key3;
+    
+    /** null-ok; value #0 */
+    private String value0;
+    
+    /** null-ok; value #1 */
+    private String value1;
+
+    /** null-ok; value #2 */
+    private String value2;
+
+    /** null-ok; value #3 */
+    private String value3;
+    
+    /**
+     * null-ok; array of additional keys and values, alternating
+     * key then value, etc. 
+     */
+    private Object[] rest;
+
+    /** bit vector (in int form) for all the "added" bits */
+    private int added;
+
+    /** &gt;= 0; number of elements in the list */
+    private int size;
+
+    // Note: Default public constructor.
+    
+    /**
+     * Adds an element. The "added" flag is set to false for the element.
+     * 
+     * @param key non-null; the key
+     * @param value non-null; the value
+     */
+    public void add(DERObjectIdentifier key, String value) {
+        add(key, value, false);
+    }
+
+    /**
+     * Adds an element.
+     * 
+     * @param key non-null; the key
+     * @param value non-null; the value
+     * @param added the added bit
+     */
+    public void add(DERObjectIdentifier key, String value, boolean added) {
+        if (size >= 32) {
+            throw new UnsupportedOperationException(
+                    "no more than 32 elements");
+        }
+
+        if (key == null) {
+            throw new NullPointerException("key == null");
+        }
+
+        if (value == null) {
+            throw new NullPointerException("value == null");
+        }
+
+        int sz = size;
+
+        switch (sz) {
+            case 0: {
+                key0 = key;
+                value0 = value;
+                break;
+            }
+            case 1: {
+                key1 = key;
+                value1 = value;
+                break;
+            }
+            case 2: {
+                key2 = key;
+                value2 = value;
+                break;
+            }
+            case 3: {
+                key3 = key;
+                value3 = value;
+                break;
+            }
+            case 4: {
+                // Do initial allocation of rest.
+                rest = new Object[10];
+                rest[0] = key;
+                rest[1] = value;
+                break;
+            }
+            case 9: {
+                // Grow to accommodate 28 pairs in the array.
+                Object[] newRest = new Object[56];
+                System.arraycopy(rest, 0, newRest, 0, 10);
+                rest = newRest;
+                // Fall through.
+            }
+            default: {
+                int index = (sz - 4) * 2;
+                rest[index] = key;
+                rest[index + 1] = value;
+                break;
+            }
+        }
+
+        if (added) {
+            this.added |= (1 << sz);
+        }
+        
+        size = sz + 1;
+    }
+
+    /**
+     * Sets the "added" flag on the most recently added element.
+     */
+    public void setLastAddedFlag() {
+        added |= 1 << (size - 1);
+    }
+
+    /**
+     * Gets the number of elements in this instance.
+     */
+    public int size() {
+        return size;
+    }
+    
+    /**
+     * Gets the nth key.
+     * 
+     * @param n index
+     * @return non-null; the nth key
+     */
+    public DERObjectIdentifier getKey(int n) {
+        if ((n < 0) || (n >= size)) {
+            throw new IndexOutOfBoundsException(Integer.toString(n));
+        }
+
+        switch (n) {
+            case 0: return key0;
+            case 1: return key1;
+            case 2: return key2;
+            case 3: return key3;
+            default: return (DERObjectIdentifier) rest[(n - 4) * 2];
+        }
+    }
+
+    /**
+     * Gets the nth value.
+     * 
+     * @param n index
+     * @return non-null; the nth value
+     */
+    public String getValue(int n) {
+        if ((n < 0) || (n >= size)) {
+            throw new IndexOutOfBoundsException(Integer.toString(n));
+        }
+
+        switch (n) {
+            case 0: return value0;
+            case 1: return value1;
+            case 2: return value2;
+            case 3: return value3;
+            default: return (String) rest[((n - 4) * 2) + 1];
+        }
+    }
+
+    /**
+     * Gets the nth added flag bit.
+     * 
+     * @param n index
+     * @return the nth added flag bit
+     */
+    public boolean getAdded(int n) {
+        if ((n < 0) || (n >= size)) {
+            throw new IndexOutOfBoundsException(Integer.toString(n));
+        }
+
+        return (added & (1 << n)) != 0;
+    }
+
+    /**
+     * Constructs and returns a new instance which consists of the
+     * elements of this one in reverse order
+     * 
+     * @return non-null; the reversed instance
+     */
+    public X509NameElementList reverse() {
+        X509NameElementList result = new X509NameElementList();
+            
+        for (int i = size - 1; i >= 0; i--) {
+            result.add(getKey(i), getValue(i), getAdded(i));
+        }
+
+        return result;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509NameEntryConverter.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509NameEntryConverter.java
new file mode 100644
index 0000000..24075f7
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509NameEntryConverter.java
@@ -0,0 +1,154 @@
+package org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.util.Strings;
+
+/**
+ * It turns out that the number of standard ways the fields in a DN should be 
+ * encoded into their ASN.1 counterparts is rapidly approaching the
+ * number of machines on the internet. By default the X509Name class 
+ * will produce UTF8Strings in line with the current recommendations (RFC 3280).
+ * <p>
+ * An example of an encoder look like below:
+ * <pre>
+ * public class X509DirEntryConverter
+ *     extends X509NameEntryConverter
+ * {
+ *     public DERObject getConvertedValue(
+ *         DERObjectIdentifier  oid,
+ *         String               value)
+ *     {
+ *         if (str.length() != 0 && str.charAt(0) == '#')
+ *         {
+ *             return convertHexEncoded(str, 1);
+ *         }
+ *         if (oid.equals(EmailAddress))
+ *         {
+ *             return new DERIA5String(str);
+ *         }
+ *         else if (canBePrintable(str))
+ *         {
+ *             return new DERPrintableString(str);
+ *         }
+ *         else if (canBeUTF8(str))
+ *         {
+ *             return new DERUTF8String(str);
+ *         }
+ *         else
+ *         {
+ *             return new DERBMPString(str);
+ *         }
+ *     }
+ * }
+ */
+public abstract class X509NameEntryConverter
+{
+    /**
+     * Convert an inline encoded hex string rendition of an ASN.1
+     * object back into its corresponding ASN.1 object.
+     * 
+     * @param str the hex encoded object
+     * @param off the index at which the encoding starts
+     * @return the decoded object
+     */
+    protected DERObject convertHexEncoded(
+        String  str,
+        int     off)
+        throws IOException
+    {
+        str = Strings.toLowerCase(str);
+        byte[] data = new byte[(str.length() - off) / 2];
+        for (int index = 0; index != data.length; index++)
+        {
+            char left = str.charAt((index * 2) + off);
+            char right = str.charAt((index * 2) + off + 1);
+            
+            if (left < 'a')
+            {
+                data[index] = (byte)((left - '0') << 4);
+            }
+            else
+            {
+                data[index] = (byte)((left - 'a' + 10) << 4);
+            }
+            if (right < 'a')
+            {
+                data[index] |= (byte)(right - '0');
+            }
+            else
+            {
+                data[index] |= (byte)(right - 'a' + 10);
+            }
+        }
+
+        ASN1InputStream aIn = new ASN1InputStream(data);
+                                            
+        return aIn.readObject();
+    }
+    
+    /**
+     * return true if the passed in String can be represented without
+     * loss as a PrintableString, false otherwise.
+     */
+    protected boolean canBePrintable(
+        String  str)
+    {
+        for (int i = str.length() - 1; i >= 0; i--)
+        {
+            char    ch = str.charAt(i);
+            
+            if (str.charAt(i) > 0x007f)
+            {
+                return false;
+            }
+            
+            if ('a' <= ch && ch <= 'z')
+            {
+                continue;
+            }
+            
+            if ('A' <= ch && ch <= 'Z')
+            {
+                continue;
+            }
+            
+            if ('0' <= ch && ch <= '9')
+            {
+                continue;
+            }
+            
+            switch (ch)
+            {
+            case ' ':
+            case '\'':
+            case '(':
+            case ')':
+            case '+':
+            case '-':
+            case '.':
+            case ':':
+            case '=':
+            case '?':
+                continue;
+            }
+            
+            return false;
+        }
+
+        return true;
+    }
+    
+    /**
+     * Convert the passed in String value into the appropriate ASN.1
+     * encoded object.
+     * 
+     * @param oid the oid associated with the value in the DN.
+     * @param value the value of the particular DN component.
+     * @return the ASN.1 equivalent for the value.
+     */
+    public abstract DERObject getConvertedValue(DERObjectIdentifier oid, String value);
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509NameTokenizer.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509NameTokenizer.java
new file mode 100644
index 0000000..035e924
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509NameTokenizer.java
@@ -0,0 +1,91 @@
+package org.bouncycastle.asn1.x509;
+
+/**
+ * class for breaking up an X500 Name into it's component tokens, ala
+ * java.util.StringTokenizer. We need this class as some of the
+ * lightweight Java environment don't support classes like
+ * StringTokenizer.
+ */
+public class X509NameTokenizer
+{
+    private String          value;
+    private int             index;
+    private char            seperator;
+    private StringBuffer    buf = new StringBuffer();
+
+    public X509NameTokenizer(
+        String  oid)
+    {
+        this(oid, ',');
+    }
+    
+    public X509NameTokenizer(
+        String  oid,
+        char    seperator)
+    {
+        this.value = oid;
+        this.index = -1;
+        this.seperator = seperator;
+    }
+
+    public boolean hasMoreTokens()
+    {
+        return (index != value.length());
+    }
+
+    public String nextToken()
+    {
+        if (index == value.length())
+        {
+            return null;
+        }
+
+        int     end = index + 1;
+        boolean quoted = false;
+        boolean escaped = false;
+
+        buf.setLength(0);
+
+        while (end != value.length())
+        {
+            char    c = value.charAt(end);
+
+            if (c == '"')
+            {
+                if (!escaped)
+                {
+                    quoted = !quoted;
+                }
+                else
+                {
+                    buf.append(c);
+                }
+                escaped = false;
+            }
+            else
+            {
+                if (escaped || quoted)
+                {
+                    buf.append(c);
+                    escaped = false;
+                }
+                else if (c == '\\')
+                {
+                    escaped = true;
+                }
+                else if (c == seperator)
+                {
+                    break;
+                }
+                else
+                {
+                    buf.append(c);
+                }
+            }
+            end++;
+        }
+
+        index = end;
+        return buf.toString().trim();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java
new file mode 100644
index 0000000..1f8b8a2
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java
@@ -0,0 +1,43 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+public interface X509ObjectIdentifiers
+{
+    //
+    // base id
+    //
+    static final String                 id                      = "2.5.4";
+
+    static final DERObjectIdentifier    commonName              = new DERObjectIdentifier(id + ".3");
+    static final DERObjectIdentifier    countryName             = new DERObjectIdentifier(id + ".6");
+    static final DERObjectIdentifier    localityName            = new DERObjectIdentifier(id + ".7");
+    static final DERObjectIdentifier    stateOrProvinceName     = new DERObjectIdentifier(id + ".8");
+    static final DERObjectIdentifier    organization            = new DERObjectIdentifier(id + ".10");
+    static final DERObjectIdentifier    organizationalUnitName  = new DERObjectIdentifier(id + ".11");
+
+    // id-SHA1 OBJECT IDENTIFIER ::=    
+    //   {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 }    //
+    static final DERObjectIdentifier    id_SHA1                 = new DERObjectIdentifier("1.3.14.3.2.26");
+
+    //
+    // ripemd160 OBJECT IDENTIFIER ::=
+    //      {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) hashAlgorithm(2) RIPEMD-160(1)}
+    //
+    static final DERObjectIdentifier    ripemd160               = new DERObjectIdentifier("1.3.36.3.2.1");
+
+    //
+    // ripemd160WithRSAEncryption OBJECT IDENTIFIER ::=
+    //      {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) signatureAlgorithm(3) rsaSignature(1) rsaSignatureWithripemd160(2) }
+    //
+    static final DERObjectIdentifier    ripemd160WithRSAEncryption = new DERObjectIdentifier("1.3.36.3.3.1.2");
+
+
+    static final DERObjectIdentifier    id_ea_rsa = new DERObjectIdentifier("2.5.8.1.1");
+    
+    //
+    //    OID for ocsp uri in AuthorityInformationAccess extension
+    //
+     static final DERObjectIdentifier ocspAccessMethod = new DERObjectIdentifier("1.3.6.1.5.5.7.48.1");
+}
+
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/BiometricData.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/BiometricData.java
new file mode 100644
index 0000000..9f373fa
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/BiometricData.java
@@ -0,0 +1,124 @@
+package org.bouncycastle.asn1.x509.qualified;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.DERIA5String;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * The BiometricData object.
+ * <pre>
+ * BiometricData  ::=  SEQUENCE {
+ *       typeOfBiometricData  TypeOfBiometricData,
+ *       hashAlgorithm        AlgorithmIdentifier,
+ *       biometricDataHash    OCTET STRING,
+ *       sourceDataUri        IA5String OPTIONAL  }
+ * </pre>
+ */
+public class BiometricData 
+    extends ASN1Encodable
+{
+    TypeOfBiometricData typeOfBiometricData;
+    AlgorithmIdentifier hashAlgorithm;
+    ASN1OctetString     biometricDataHash;
+    DERIA5String        sourceDataUri;    
+    
+    public static BiometricData getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof BiometricData)
+        {
+            return (BiometricData)obj;
+        }
+
+        if (obj instanceof ASN1Sequence)
+        {
+            return new BiometricData(ASN1Sequence.getInstance(obj));            
+        }
+        else
+        {
+            throw new IllegalArgumentException("unknown object in getInstance");
+        }
+    }                
+            
+    public BiometricData(ASN1Sequence seq)
+    {
+        Enumeration e = seq.getObjects();
+
+        // typeOfBiometricData
+        typeOfBiometricData = TypeOfBiometricData.getInstance(e.nextElement());
+        // hashAlgorithm
+        hashAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement());
+        // biometricDataHash
+        biometricDataHash = ASN1OctetString.getInstance(e.nextElement());
+        // sourceDataUri
+        if (e.hasMoreElements())
+        {
+            sourceDataUri = DERIA5String.getInstance(e.nextElement());
+        }
+    }
+    
+    public BiometricData(
+        TypeOfBiometricData typeOfBiometricData,
+        AlgorithmIdentifier hashAlgorithm,
+        ASN1OctetString     biometricDataHash,
+        DERIA5String        sourceDataUri)
+    {
+        this.typeOfBiometricData = typeOfBiometricData;
+        this.hashAlgorithm = hashAlgorithm;
+        this.biometricDataHash = biometricDataHash;
+        this.sourceDataUri = sourceDataUri;
+    }
+    
+    public BiometricData(
+        TypeOfBiometricData typeOfBiometricData,
+        AlgorithmIdentifier hashAlgorithm,
+        ASN1OctetString     biometricDataHash)
+    {
+        this.typeOfBiometricData = typeOfBiometricData;
+        this.hashAlgorithm = hashAlgorithm;
+        this.biometricDataHash = biometricDataHash;
+        this.sourceDataUri = null;
+    }
+
+    public TypeOfBiometricData getTypeOfBiometricData()
+    {
+        return typeOfBiometricData;
+    }
+    
+    public AlgorithmIdentifier getHashAlgorithm()
+    {
+        return hashAlgorithm;
+    }
+    
+    public ASN1OctetString getBiometricDataHash()
+    {
+        return biometricDataHash;
+    }
+    
+    public DERIA5String getSourceDataUri()
+    {
+        return sourceDataUri;
+    }
+    
+    public DERObject toASN1Object() 
+    {
+        ASN1EncodableVector seq = new ASN1EncodableVector();
+        seq.add(typeOfBiometricData);
+        seq.add(hashAlgorithm);
+        seq.add(biometricDataHash); 
+        
+        if (sourceDataUri != null)
+        {
+            seq.add(sourceDataUri);
+        }
+
+        return new DERSequence(seq);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/ETSIQCObjectIdentifiers.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/ETSIQCObjectIdentifiers.java
new file mode 100644
index 0000000..eef97e3
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/ETSIQCObjectIdentifiers.java
@@ -0,0 +1,16 @@
+package org.bouncycastle.asn1.x509.qualified;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+public interface ETSIQCObjectIdentifiers
+{
+    //
+    // base id
+    //
+    static final String                 id_etsi_qcs                  = "0.4.0.1862.1";
+
+    static final DERObjectIdentifier    id_etsi_qcs_QcCompliance     = new DERObjectIdentifier(id_etsi_qcs+".1");
+    static final DERObjectIdentifier    id_etsi_qcs_LimiteValue      = new DERObjectIdentifier(id_etsi_qcs+".2");
+    static final DERObjectIdentifier    id_etsi_qcs_RetentionPeriod  = new DERObjectIdentifier(id_etsi_qcs+".3");
+    static final DERObjectIdentifier    id_etsi_qcs_QcSSCD           = new DERObjectIdentifier(id_etsi_qcs+".4");
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/Iso4217CurrencyCode.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/Iso4217CurrencyCode.java
new file mode 100644
index 0000000..10ced50
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/Iso4217CurrencyCode.java
@@ -0,0 +1,93 @@
+package org.bouncycastle.asn1.x509.qualified;
+
+import org.bouncycastle.asn1.ASN1Choice;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERPrintableString;
+
+/**
+ * The Iso4217CurrencyCode object.
+ * <pre>
+ * Iso4217CurrencyCode  ::=  CHOICE {
+ *       alphabetic              PrintableString (SIZE 3), --Recommended
+ *       numeric              INTEGER (1..999) }
+ * -- Alphabetic or numeric currency code as defined in ISO 4217
+ * -- It is recommended that the Alphabetic form is used
+ * </pre>
+ */
+public class Iso4217CurrencyCode 
+    extends ASN1Encodable
+    implements ASN1Choice
+{
+    final int ALPHABETIC_MAXSIZE = 3;
+    final int NUMERIC_MINSIZE = 1;
+    final int NUMERIC_MAXSIZE = 999;
+    
+    DEREncodable obj;    
+    int          numeric;
+    
+    public static Iso4217CurrencyCode getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof Iso4217CurrencyCode)
+        {
+            return (Iso4217CurrencyCode)obj;
+        }
+
+        if (obj instanceof DERInteger)
+        {
+            DERInteger numericobj = DERInteger.getInstance(obj);
+            int numeric = numericobj.getValue().intValue();  
+            return new Iso4217CurrencyCode(numeric);            
+        }
+        else
+        if (obj instanceof DERPrintableString)
+        {
+            DERPrintableString alphabetic = DERPrintableString.getInstance(obj);
+            return new Iso4217CurrencyCode(alphabetic.getString());
+        }
+        throw new IllegalArgumentException("unknown object in getInstance");
+    }
+            
+    public Iso4217CurrencyCode(
+        int numeric)
+    {
+        if (numeric > NUMERIC_MAXSIZE || numeric < NUMERIC_MINSIZE)
+        {
+            throw new IllegalArgumentException("wrong size in numeric code : not in (" +NUMERIC_MINSIZE +".."+ NUMERIC_MAXSIZE +")");
+        }
+        obj = new DERInteger(numeric);
+    }
+    
+    public Iso4217CurrencyCode(
+        String alphabetic)
+    {
+        if (alphabetic.length() > ALPHABETIC_MAXSIZE)
+        {
+            throw new IllegalArgumentException("wrong size in alphabetic code : max size is " + ALPHABETIC_MAXSIZE);
+        }
+        obj = new DERPrintableString(alphabetic);
+    }            
+
+    public boolean isAlphabetic()
+    {
+        return obj instanceof DERPrintableString;
+    }
+    
+    public String getAlphabetic()
+    {
+        return ((DERPrintableString)obj).getString();
+    }
+    
+    public int getNumeric()
+    {
+        return ((DERInteger)obj).getValue().intValue();
+    }
+    
+    public DERObject toASN1Object() 
+    {    
+        return obj.getDERObject();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/MonetaryValue.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/MonetaryValue.java
new file mode 100644
index 0000000..c8c0ce3
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/MonetaryValue.java
@@ -0,0 +1,92 @@
+package org.bouncycastle.asn1.x509.qualified;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERSequence;
+
+/**
+ * The MonetaryValue object.
+ * <pre>
+ * MonetaryValue  ::=  SEQUENCE {
+ *       currency              Iso4217CurrencyCode,
+ *       amount               INTEGER, 
+ *       exponent             INTEGER }
+ * -- value = amount * 10^exponent
+ * </pre>
+ */
+public class MonetaryValue 
+    extends ASN1Encodable
+{
+    Iso4217CurrencyCode currency;
+    DERInteger          amount;
+    DERInteger          exponent;
+        
+    public static MonetaryValue getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof MonetaryValue)
+        {
+            return (MonetaryValue)obj;
+        }
+
+        if (obj instanceof ASN1Sequence)
+        {
+            return new MonetaryValue(ASN1Sequence.getInstance(obj));            
+        }
+        
+        throw new IllegalArgumentException("unknown object in getInstance");
+    }
+        
+    public MonetaryValue(
+        ASN1Sequence seq)
+    {
+        Enumeration e = seq.getObjects();    
+        // currency
+        currency = Iso4217CurrencyCode.getInstance(e.nextElement());
+        // hashAlgorithm
+        amount = DERInteger.getInstance(e.nextElement());
+        // exponent
+        exponent = DERInteger.getInstance(e.nextElement());            
+    }
+        
+    public MonetaryValue(
+        Iso4217CurrencyCode currency, 
+        int                 amount, 
+        int                 exponent)
+    {    
+        this.currency = currency;
+        this.amount = new DERInteger(amount);
+        this.exponent = new DERInteger(exponent);                  
+    }                    
+             
+    public Iso4217CurrencyCode getCurrency()
+    {
+        return currency;
+    }
+        
+    public BigInteger getAmount()
+    {
+        return amount.getValue();
+    }
+        
+    public BigInteger getExponent()
+    {
+        return exponent.getValue();
+    }   
+    
+    public DERObject toASN1Object() 
+    {
+        ASN1EncodableVector seq = new ASN1EncodableVector();
+        seq.add(currency);
+        seq.add(amount);
+        seq.add(exponent); 
+        
+        return new DERSequence(seq);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/QCStatement.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/QCStatement.java
new file mode 100644
index 0000000..6b87ea0
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/QCStatement.java
@@ -0,0 +1,95 @@
+package org.bouncycastle.asn1.x509.qualified;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+
+/**
+ * The QCStatement object.
+ * <pre>
+ * QCStatement ::= SEQUENCE {
+ *   statementId        OBJECT IDENTIFIER,
+ *   statementInfo      ANY DEFINED BY statementId OPTIONAL} 
+ * </pre>
+ */
+
+public class QCStatement 
+    extends ASN1Encodable 
+    implements ETSIQCObjectIdentifiers, RFC3739QCObjectIdentifiers
+{
+    DERObjectIdentifier qcStatementId;
+    ASN1Encodable       qcStatementInfo;
+
+    public static QCStatement getInstance(
+        Object obj)
+    {
+        if (obj == null || obj instanceof QCStatement)
+        {
+            return (QCStatement)obj;
+        }
+
+        if (obj instanceof ASN1Sequence)
+        {
+            return new QCStatement(ASN1Sequence.getInstance(obj));            
+        }
+        
+        throw new IllegalArgumentException("unknown object in getInstance");
+    }    
+    
+    public QCStatement(
+        ASN1Sequence seq)
+    {
+        Enumeration e = seq.getObjects();
+
+        // qcStatementId
+        qcStatementId = DERObjectIdentifier.getInstance(e.nextElement());
+        // qcstatementInfo
+        if (e.hasMoreElements())
+        {
+            qcStatementInfo = (ASN1Encodable) e.nextElement();
+        }
+    }    
+    
+    public QCStatement(
+        DERObjectIdentifier qcStatementId)
+    {
+        this.qcStatementId = qcStatementId;
+        this.qcStatementInfo = null;
+    }
+    
+    public QCStatement(
+        DERObjectIdentifier qcStatementId, 
+        ASN1Encodable       qcStatementInfo)
+    {
+        this.qcStatementId = qcStatementId;
+        this.qcStatementInfo = qcStatementInfo;
+    }    
+        
+    public DERObjectIdentifier getStatementId()
+    {
+        return qcStatementId;
+    }
+    
+    public ASN1Encodable getStatementInfo()
+    {
+        return qcStatementInfo;
+    }
+
+    public DERObject toASN1Object() 
+    {
+        ASN1EncodableVector seq = new ASN1EncodableVector();
+        seq.add(qcStatementId);       
+        
+        if (qcStatementInfo != null)
+        {
+            seq.add(qcStatementInfo);
+        }
+
+        return new DERSequence(seq);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/RFC3739QCObjectIdentifiers.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/RFC3739QCObjectIdentifiers.java
new file mode 100644
index 0000000..8762f2f
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/RFC3739QCObjectIdentifiers.java
@@ -0,0 +1,14 @@
+package org.bouncycastle.asn1.x509.qualified;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+public interface RFC3739QCObjectIdentifiers
+{
+    //
+    // base id
+    //
+    static final String                 id_qcs             = "1.3.6.1.5.5.7.11";
+
+    static final DERObjectIdentifier    id_qcs_pkixQCSyntax_v1                = new DERObjectIdentifier(id_qcs+".1");
+    static final DERObjectIdentifier    id_qcs_pkixQCSyntax_v2                 = new DERObjectIdentifier(id_qcs+".2");
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/SemanticsInformation.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/SemanticsInformation.java
new file mode 100644
index 0000000..445e8b2
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/SemanticsInformation.java
@@ -0,0 +1,130 @@
+package org.bouncycastle.asn1.x509.qualified;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.GeneralName;
+
+/**
+ * The SemanticsInformation object.
+ * <pre>
+ *       SemanticsInformation ::= SEQUENCE {
+ *         semanticsIdentifier        OBJECT IDENTIFIER   OPTIONAL,
+ *         nameRegistrationAuthorities NameRegistrationAuthorities
+ *                                                         OPTIONAL }
+ *         (WITH COMPONENTS {..., semanticsIdentifier PRESENT}|
+ *          WITH COMPONENTS {..., nameRegistrationAuthorities PRESENT})
+ *
+ *     NameRegistrationAuthorities ::=  SEQUENCE SIZE (1..MAX) OF
+ *         GeneralName
+ * </pre>
+ */
+public class SemanticsInformation extends ASN1Encodable
+{
+    DERObjectIdentifier semanticsIdentifier;
+    GeneralName[] nameRegistrationAuthorities;    
+    
+    public static SemanticsInformation getInstance(Object obj)
+    {
+        if (obj == null || obj instanceof SemanticsInformation)
+        {
+            return (SemanticsInformation)obj;
+        }
+
+        if (obj instanceof ASN1Sequence)
+        {
+            return new SemanticsInformation(ASN1Sequence.getInstance(obj));            
+        }
+        
+        throw new IllegalArgumentException("unknown object in getInstance");
+    }
+        
+    public SemanticsInformation(ASN1Sequence seq)
+    {
+        Enumeration e = seq.getObjects();
+        if (seq.size() < 1)
+        {
+             throw new IllegalArgumentException("no objects in SemanticsInformation");
+        }
+        
+        Object object = e.nextElement();
+        if (object instanceof DERObjectIdentifier)
+        {
+            semanticsIdentifier = DERObjectIdentifier.getInstance(object);
+            if (e.hasMoreElements())
+            {
+                object = e.nextElement();
+            }
+            else
+            {
+                object = null;
+            }
+        }
+        
+        if (object != null)
+        {
+            ASN1Sequence generalNameSeq = ASN1Sequence.getInstance(object);
+            nameRegistrationAuthorities = new GeneralName[generalNameSeq.size()];
+            for (int i= 0; i < generalNameSeq.size(); i++)
+            {
+                nameRegistrationAuthorities[i] = GeneralName.getInstance(generalNameSeq.getObjectAt(i));
+            } 
+        }
+    }
+        
+    public SemanticsInformation(
+        DERObjectIdentifier semanticsIdentifier,
+        GeneralName[] generalNames)
+    {
+        this.semanticsIdentifier = semanticsIdentifier;
+        this.nameRegistrationAuthorities = generalNames;
+    }
+
+    public SemanticsInformation(DERObjectIdentifier semanticsIdentifier)
+    {
+        this.semanticsIdentifier = semanticsIdentifier;
+        this.nameRegistrationAuthorities = null;
+    }
+
+    public SemanticsInformation(GeneralName[] generalNames)
+    {
+        this.semanticsIdentifier = null;
+        this.nameRegistrationAuthorities = generalNames;
+    }        
+    
+    public DERObjectIdentifier getSemanticsIdentifier()
+    {
+        return semanticsIdentifier;
+    }
+        
+    public GeneralName[] getNameRegistrationAuthorities()
+    {
+        return nameRegistrationAuthorities;
+    } 
+    
+    public DERObject toASN1Object() 
+    {
+        ASN1EncodableVector seq = new ASN1EncodableVector();
+        
+        if (this.semanticsIdentifier != null)
+        {
+            seq.add(semanticsIdentifier);
+        }
+        if (this.nameRegistrationAuthorities != null)
+        {
+            ASN1EncodableVector seqname = new ASN1EncodableVector();
+            for (int i = 0; i < nameRegistrationAuthorities.length; i++) 
+            {
+                seqname.add(nameRegistrationAuthorities[i]);
+            }            
+            seq.add(new DERSequence(seqname));
+        }            
+        
+        return new DERSequence(seq);
+    }                   
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/TypeOfBiometricData.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/TypeOfBiometricData.java
new file mode 100644
index 0000000..3ab384a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/qualified/TypeOfBiometricData.java
@@ -0,0 +1,90 @@
+package org.bouncycastle.asn1.x509.qualified;
+
+import org.bouncycastle.asn1.ASN1Choice;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+/**
+ * The TypeOfBiometricData object.
+ * <pre>
+ * TypeOfBiometricData ::= CHOICE {
+ *   predefinedBiometricType   PredefinedBiometricType,
+ *   biometricDataOid          OBJECT IDENTIFIER }
+ *
+ * PredefinedBiometricType ::= INTEGER {
+ *   picture(0),handwritten-signature(1)}
+ *   (picture|handwritten-signature)
+ * </pre>
+ */
+public class TypeOfBiometricData  
+    extends ASN1Encodable
+    implements ASN1Choice
+{
+    public static final int PICTURE                     = 0;
+    public static final int HANDWRITTEN_SIGNATURE       = 1;
+
+    DEREncodable      obj;
+
+    public static TypeOfBiometricData getInstance(Object obj)
+    {
+        if (obj == null || obj instanceof TypeOfBiometricData)
+        {
+            return (TypeOfBiometricData)obj;
+        }
+
+        if (obj instanceof DERInteger)
+        {
+            DERInteger predefinedBiometricTypeObj = DERInteger.getInstance(obj);
+            int  predefinedBiometricType = predefinedBiometricTypeObj.getValue().intValue();
+
+            return new TypeOfBiometricData(predefinedBiometricType);
+        }
+        else if (obj instanceof DERObjectIdentifier)
+        {
+            DERObjectIdentifier BiometricDataID = DERObjectIdentifier.getInstance(obj);
+            return new TypeOfBiometricData(BiometricDataID);
+        }
+
+        throw new IllegalArgumentException("unknown object in getInstance");
+    }
+        
+    public TypeOfBiometricData(int predefinedBiometricType)
+    {
+        if (predefinedBiometricType == PICTURE || predefinedBiometricType == HANDWRITTEN_SIGNATURE)
+        {
+                obj = new DERInteger(predefinedBiometricType);
+        }
+        else
+        {
+            throw new IllegalArgumentException("unknow PredefinedBiometricType : " + predefinedBiometricType);
+        }        
+    }
+    
+    public TypeOfBiometricData(DERObjectIdentifier BiometricDataID)
+    {
+        obj = BiometricDataID;
+    }
+    
+    public boolean isPredefined()
+    {
+        return obj instanceof DERInteger;
+    }
+    
+    public int getPredefinedBiometricType()
+    {
+        return ((DERInteger)obj).getValue().intValue();
+    }
+    
+    public DERObjectIdentifier getBiometricDataOid()
+    {
+        return (DERObjectIdentifier)obj;
+    }
+    
+    public DERObject toASN1Object() 
+    {        
+        return obj.getDERObject();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x509/sigi/SigIObjectIdentifiers.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/sigi/SigIObjectIdentifiers.java
new file mode 100644
index 0000000..73fc962
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x509/sigi/SigIObjectIdentifiers.java
@@ -0,0 +1,49 @@
+package org.bouncycastle.asn1.x509.sigi;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+/**
+ * Object Identifiers of SigI specifciation (German Signature Law
+ * Interoperability specification).
+ */
+public final class SigIObjectIdentifiers
+{
+    private SigIObjectIdentifiers()
+    {
+    }
+
+    public final static DERObjectIdentifier id_sigi = new DERObjectIdentifier("1.3.36.8");
+
+    /**
+     * Key purpose IDs for German SigI (Signature Interoperability
+     * Specification)
+     */
+    public final static DERObjectIdentifier id_sigi_kp = new DERObjectIdentifier(id_sigi + ".2");
+
+    /**
+     * Certificate policy IDs for German SigI (Signature Interoperability
+     * Specification)
+     */
+    public final static DERObjectIdentifier id_sigi_cp = new DERObjectIdentifier(id_sigi + ".1");
+
+    /**
+     * Other Name IDs for German SigI (Signature Interoperability Specification)
+     */
+    public final static DERObjectIdentifier id_sigi_on = new DERObjectIdentifier(id_sigi + ".4");
+
+    /**
+     * To be used for for the generation of directory service certificates.
+     */
+    public static final DERObjectIdentifier id_sigi_kp_directoryService = new DERObjectIdentifier(id_sigi_kp + ".1");
+
+    /**
+     * ID for PersonalData
+     */
+    public static final DERObjectIdentifier id_sigi_on_personalData = new DERObjectIdentifier(id_sigi_on + ".1");
+
+    /**
+     * Certificate is conform to german signature law.
+     */
+    public static final DERObjectIdentifier id_sigi_cp_sigconform = new DERObjectIdentifier(id_sigi_cp + ".1");
+
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java b/libcore/security/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java
new file mode 100644
index 0000000..c313572
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java
@@ -0,0 +1,121 @@
+package org.bouncycastle.asn1.x9;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+public interface X9ObjectIdentifiers
+{
+    //
+    // X9.62
+    //
+    // ansi-X9-62 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+    //            us(840) ansi-x962(10045) }
+    //
+    static final String    ansi_X9_62 = "1.2.840.10045";
+    static final String    id_fieldType = ansi_X9_62 + ".1";
+
+    static final DERObjectIdentifier    prime_field
+                    = new DERObjectIdentifier(id_fieldType + ".1");
+
+    static final DERObjectIdentifier    characteristic_two_field
+                    = new DERObjectIdentifier(id_fieldType + ".2");
+
+    static final DERObjectIdentifier    gnBasis
+                    = new DERObjectIdentifier(id_fieldType + ".2.3.1");
+
+    static final DERObjectIdentifier    tpBasis
+                    = new DERObjectIdentifier(id_fieldType + ".2.3.2");
+
+    static final DERObjectIdentifier    ppBasis
+                    = new DERObjectIdentifier(id_fieldType + ".2.3.3");
+
+    static final String    id_ecSigType = ansi_X9_62 + ".4";
+
+    static final DERObjectIdentifier    ecdsa_with_SHA1
+                    = new DERObjectIdentifier(id_ecSigType + ".1");
+
+    static final String    id_publicKeyType = ansi_X9_62 + ".2";
+
+    static final DERObjectIdentifier    id_ecPublicKey
+                    = new DERObjectIdentifier(id_publicKeyType + ".1");
+
+    static final DERObjectIdentifier    ecdsa_with_SHA2
+                    = new DERObjectIdentifier(id_ecSigType + ".3");
+
+    static final DERObjectIdentifier    ecdsa_with_SHA224
+                    = new DERObjectIdentifier(ecdsa_with_SHA2 + ".1");
+
+    static final DERObjectIdentifier    ecdsa_with_SHA256
+                    = new DERObjectIdentifier(ecdsa_with_SHA2 + ".2");
+
+    static final DERObjectIdentifier    ecdsa_with_SHA384
+                    = new DERObjectIdentifier(ecdsa_with_SHA2 + ".3");
+
+    static final DERObjectIdentifier    ecdsa_with_SHA512
+                    = new DERObjectIdentifier(ecdsa_with_SHA2 + ".4");
+
+    //
+    // named curves
+    //
+    static final String     ellipticCurve = ansi_X9_62 + ".3";
+
+    //
+    // Two Curves
+    //
+    static final String     cTwoCurve = ellipticCurve + ".0";
+    
+    static final DERObjectIdentifier    c2pnb163v1 = new DERObjectIdentifier(cTwoCurve + ".1");
+    static final DERObjectIdentifier    c2pnb163v2 = new DERObjectIdentifier(cTwoCurve + ".2");
+    static final DERObjectIdentifier    c2pnb163v3 = new DERObjectIdentifier(cTwoCurve + ".3");
+    static final DERObjectIdentifier    c2pnb176w1 = new DERObjectIdentifier(cTwoCurve + ".4");
+    static final DERObjectIdentifier    c2tnb191v1 = new DERObjectIdentifier(cTwoCurve + ".5");
+    static final DERObjectIdentifier    c2tnb191v2 = new DERObjectIdentifier(cTwoCurve + ".6");
+    static final DERObjectIdentifier    c2tnb191v3 = new DERObjectIdentifier(cTwoCurve + ".7");
+    static final DERObjectIdentifier    c2onb191v4 = new DERObjectIdentifier(cTwoCurve + ".8");
+    static final DERObjectIdentifier    c2onb191v5 = new DERObjectIdentifier(cTwoCurve + ".9");
+    static final DERObjectIdentifier    c2pnb208w1 = new DERObjectIdentifier(cTwoCurve + ".10");
+    static final DERObjectIdentifier    c2tnb239v1 = new DERObjectIdentifier(cTwoCurve + ".11");
+    static final DERObjectIdentifier    c2tnb239v2 = new DERObjectIdentifier(cTwoCurve + ".12");
+    static final DERObjectIdentifier    c2tnb239v3 = new DERObjectIdentifier(cTwoCurve + ".13");
+    static final DERObjectIdentifier    c2onb239v4 = new DERObjectIdentifier(cTwoCurve + ".14");
+    static final DERObjectIdentifier    c2onb239v5 = new DERObjectIdentifier(cTwoCurve + ".15");
+    static final DERObjectIdentifier    c2pnb272w1 = new DERObjectIdentifier(cTwoCurve + ".16");
+    static final DERObjectIdentifier    c2png304v1 = new DERObjectIdentifier(cTwoCurve + ".17");
+    static final DERObjectIdentifier    c2tnb359v1 = new DERObjectIdentifier(cTwoCurve + ".18");
+    static final DERObjectIdentifier    c2pnb368w1 = new DERObjectIdentifier(cTwoCurve + ".19");
+    static final DERObjectIdentifier    c2tnb431r1 = new DERObjectIdentifier(cTwoCurve + ".20");
+    
+    //
+    // Prime
+    //
+    static final String     primeCurve = ellipticCurve + ".1";
+
+    static final DERObjectIdentifier    prime192v1 = new DERObjectIdentifier(primeCurve + ".1");
+    static final DERObjectIdentifier    prime192v2 = new DERObjectIdentifier(primeCurve + ".2");
+    static final DERObjectIdentifier    prime192v3 = new DERObjectIdentifier(primeCurve + ".3");
+    static final DERObjectIdentifier    prime239v1 = new DERObjectIdentifier(primeCurve + ".4");
+    static final DERObjectIdentifier    prime239v2 = new DERObjectIdentifier(primeCurve + ".5");
+    static final DERObjectIdentifier    prime239v3 = new DERObjectIdentifier(primeCurve + ".6");
+    static final DERObjectIdentifier    prime256v1 = new DERObjectIdentifier(primeCurve + ".7");
+
+    //
+    // Diffie-Hellman
+    //
+    // dhpublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+    //            us(840) ansi-x942(10046) number-type(2) 1 }
+    //
+    static final DERObjectIdentifier    dhpublicnumber = new DERObjectIdentifier("1.2.840.10046.2.1");
+
+    //
+    // DSA
+    //
+    // dsapublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+    //            us(840) ansi-x957(10040) number-type(4) 1 }
+    static final DERObjectIdentifier    id_dsa = new DERObjectIdentifier("1.2.840.10040.4.1");
+
+    /**
+     *   id-dsa-with-sha1 OBJECT IDENTIFIER ::=  { iso(1) member-body(2)
+     *         us(840) x9-57 (10040) x9cm(4) 3 }
+     */
+    public static final DERObjectIdentifier id_dsa_with_sha1 = new DERObjectIdentifier("1.2.840.10040.4.3");
+}
+
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/AsymmetricBlockCipher.java b/libcore/security/src/main/java/org/bouncycastle/crypto/AsymmetricBlockCipher.java
new file mode 100644
index 0000000..565effc
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/AsymmetricBlockCipher.java
@@ -0,0 +1,45 @@
+package org.bouncycastle.crypto;
+
+
+/**
+ * base interface that a public/private key block cipher needs
+ * to conform to.
+ */
+public interface AsymmetricBlockCipher
+{
+    /**
+     * initialise the cipher.
+     *
+     * @param forEncryption if true the cipher is initialised for 
+     *  encryption, if false for decryption.
+     * @param param the key and other data required by the cipher.
+     */
+    public void init(boolean forEncryption, CipherParameters param);
+
+    /**
+     * returns the largest size an input block can be.
+     *
+     * @return maximum size for an input block.
+     */
+    public int getInputBlockSize();
+
+    /**
+     * returns the maximum size of the block produced by this cipher.
+     *
+     * @return maximum size of the output block produced by the cipher.
+     */
+    public int getOutputBlockSize();
+
+    /**
+     * process the block of len bytes stored in in from offset inOff.
+     *
+     * @param in the input data
+     * @param inOff offset into the in array where the data starts
+     * @param len the length of the block to be processed.
+     * @return the resulting byte array of the encryption/decryption process.
+     * @exception InvalidCipherTextException data decrypts improperly.
+     * @exception DataLengthException the input data is too large for the cipher.
+     */
+    public byte[] processBlock(byte[] in, int inOff, int len)
+        throws InvalidCipherTextException;
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/AsymmetricCipherKeyPair.java b/libcore/security/src/main/java/org/bouncycastle/crypto/AsymmetricCipherKeyPair.java
new file mode 100644
index 0000000..85bec73
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/AsymmetricCipherKeyPair.java
@@ -0,0 +1,44 @@
+package org.bouncycastle.crypto;
+
+/**
+ * a holding class for public/private parameter pairs.
+ */
+public class AsymmetricCipherKeyPair
+{
+    private CipherParameters    publicParam;
+    private CipherParameters    privateParam;
+
+    /**
+     * basic constructor.
+     *
+     * @param publicParam a public key parameters object.
+     * @param privateParam the corresponding private key parameters.
+     */
+    public AsymmetricCipherKeyPair(
+        CipherParameters    publicParam,
+        CipherParameters    privateParam)
+    {
+        this.publicParam = publicParam;
+        this.privateParam = privateParam;
+    }
+
+    /**
+     * return the public key parameters.
+     *
+     * @return the public key parameters.
+     */
+    public CipherParameters getPublic()
+    {
+        return publicParam;
+    }
+
+    /**
+     * return the private key parameters.
+     *
+     * @return the private key parameters.
+     */
+    public CipherParameters getPrivate()
+    {
+        return privateParam;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/AsymmetricCipherKeyPairGenerator.java b/libcore/security/src/main/java/org/bouncycastle/crypto/AsymmetricCipherKeyPairGenerator.java
new file mode 100644
index 0000000..919db19
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/AsymmetricCipherKeyPairGenerator.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.crypto;
+
+/**
+ * interface that a public/private key pair generator should conform to.
+ */
+public interface AsymmetricCipherKeyPairGenerator
+{
+    /**
+     * intialise the key pair generator.
+     *
+     * @param param the parameters the key pair is to be initialised with.
+     */
+    public void init(KeyGenerationParameters param);
+
+    /**
+     * return an AsymmetricCipherKeyPair containing the generated keys.
+     *
+     * @return an AsymmetricCipherKeyPair containing the generated keys.
+     */
+    public AsymmetricCipherKeyPair generateKeyPair();
+}
+
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/BasicAgreement.java b/libcore/security/src/main/java/org/bouncycastle/crypto/BasicAgreement.java
new file mode 100644
index 0000000..4907427
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/BasicAgreement.java
@@ -0,0 +1,21 @@
+package org.bouncycastle.crypto;
+
+import java.math.BigInteger;
+
+/**
+ * The basic interface that basic Diffie-Hellman implementations
+ * conforms to.
+ */
+public interface BasicAgreement
+{
+    /**
+     * initialise the agreement engine.
+     */
+    public void init(CipherParameters param);
+
+    /**
+     * given a public key from a given party calculate the next
+     * message in the agreement sequence. 
+     */
+    public BigInteger calculateAgreement(CipherParameters pubKey);
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/BlockCipher.java b/libcore/security/src/main/java/org/bouncycastle/crypto/BlockCipher.java
new file mode 100644
index 0000000..3cfa25a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/BlockCipher.java
@@ -0,0 +1,56 @@
+package org.bouncycastle.crypto;
+
+
+/**
+ * Block cipher engines are expected to conform to this interface.
+ */
+public interface BlockCipher
+{
+    /**
+     * Initialise the cipher.
+     *
+     * @param forEncryption if true the cipher is initialised for
+     *  encryption, if false for decryption.
+     * @param params the key and other data required by the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(boolean forEncryption, CipherParameters params)
+        throws IllegalArgumentException;
+
+    /**
+     * Return the name of the algorithm the cipher implements.
+     *
+     * @return the name of the algorithm the cipher implements.
+     */
+    public String getAlgorithmName();
+
+    /**
+     * Return the block size for this cipher (in bytes).
+     *
+     * @return the block size for this cipher in bytes.
+     */
+    public int getBlockSize();
+
+    /**
+     * Process one block of input from the array in and write it to
+     * the out array.
+     *
+     * @param in the array containing the input data.
+     * @param inOff offset into the in array the data starts at.
+     * @param out the array the output data will be copied into.
+     * @param outOff the offset into the out array the output will start at.
+     * @exception DataLengthException if there isn't enough data in in, or
+     * space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     * @return the number of bytes processed and produced.
+     */
+    public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
+        throws DataLengthException, IllegalStateException;
+
+    /**
+     * Reset the cipher. After resetting the cipher is in the same state
+     * as it was after the last init (if there was one).
+     */
+    public void reset();
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/BufferedAsymmetricBlockCipher.java b/libcore/security/src/main/java/org/bouncycastle/crypto/BufferedAsymmetricBlockCipher.java
new file mode 100644
index 0000000..205132e
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/BufferedAsymmetricBlockCipher.java
@@ -0,0 +1,167 @@
+package org.bouncycastle.crypto;
+
+/**
+ * a buffer wrapper for an asymmetric block cipher, allowing input
+ * to be accumulated in a piecemeal fashion until final processing.
+ */
+public class BufferedAsymmetricBlockCipher
+{
+    protected byte[]        buf;
+    protected int           bufOff;
+
+    private final AsymmetricBlockCipher   cipher;
+
+    /**
+     * base constructor.
+     *
+     * @param cipher the cipher this buffering object wraps.
+     */
+    public BufferedAsymmetricBlockCipher(
+        AsymmetricBlockCipher     cipher)
+    {
+        this.cipher = cipher;
+    }
+
+    /**
+     * return the underlying cipher for the buffer.
+     *
+     * @return the underlying cipher for the buffer.
+     */
+    public AsymmetricBlockCipher getUnderlyingCipher()
+    {
+        return cipher;
+    }
+
+    /**
+     * return the amount of data sitting in the buffer.
+     *
+     * @return the amount of data sitting in the buffer.
+     */
+    public int getBufferPosition()
+    {
+        return bufOff;
+    }
+
+    /**
+     * initialise the buffer and the underlying cipher.
+     *
+     * @param forEncryption if true the cipher is initialised for
+     *  encryption, if false for decryption.
+     * @param params the key and other data required by the cipher.
+     */
+    public void init(
+        boolean             forEncryption,
+        CipherParameters    params)
+    {
+        reset();
+
+        cipher.init(forEncryption, params);
+
+        buf = new byte[cipher.getInputBlockSize()];
+        bufOff = 0;
+    }
+
+    /**
+     * returns the largest size an input block can be.
+     *
+     * @return maximum size for an input block.
+     */
+    public int getInputBlockSize()
+    {
+        return cipher.getInputBlockSize();
+    }
+
+    /**
+     * returns the maximum size of the block produced by this cipher.
+     *
+     * @return maximum size of the output block produced by the cipher.
+     */
+    public int getOutputBlockSize()
+    {
+        return cipher.getOutputBlockSize();
+    }
+
+    /**
+     * add another byte for processing.
+     * 
+     * @param in the input byte.
+     */
+    public void processByte(
+        byte        in)
+    {
+        if (bufOff > buf.length)
+        {
+            throw new DataLengthException("attempt to process message to long for cipher");
+        }
+
+        buf[bufOff++] = in;
+    }
+
+    /**
+     * add len bytes to the buffer for processing.
+     *
+     * @param in the input data
+     * @param inOff offset into the in array where the data starts
+     * @param len the length of the block to be processed.
+     */
+    public void processBytes(
+        byte[]      in,
+        int         inOff,
+        int         len)
+    {
+        if (len == 0)
+        {
+            return;
+        }
+
+        if (len < 0)
+        {
+            throw new IllegalArgumentException("Can't have a negative input length!");
+        }
+
+        if (bufOff + len > buf.length)
+        {
+            throw new DataLengthException("attempt to process message to long for cipher");
+        }
+
+        System.arraycopy(in, inOff, buf, bufOff, len);
+        bufOff += len;
+    }
+
+    /**
+     * process the contents of the buffer using the underlying
+     * cipher.
+     *
+     * @return the result of the encryption/decryption process on the
+     * buffer.
+     * @exception InvalidCipherTextException if we are given a garbage block.
+     */
+    public byte[] doFinal()
+        throws InvalidCipherTextException
+    {
+        byte[] out = cipher.processBlock(buf, 0, bufOff);
+
+        reset();
+
+        return out;
+    }
+
+    /**
+     * Reset the buffer and the underlying cipher.
+     */
+    public void reset()
+    {
+        /*
+         * clean the buffer.
+         */
+        if (buf != null)
+        {
+            for (int i = 0; i < buf.length; i++)
+            {
+                buf[0] = 0;
+            }
+        }
+
+        bufOff = 0;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java b/libcore/security/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java
new file mode 100644
index 0000000..53d776a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java
@@ -0,0 +1,322 @@
+package org.bouncycastle.crypto;
+
+
+/**
+ * A wrapper class that allows block ciphers to be used to process data in
+ * a piecemeal fashion. The BufferedBlockCipher outputs a block only when the
+ * buffer is full and more data is being added, or on a doFinal.
+ * <p>
+ * Note: in the case where the underlying cipher is either a CFB cipher or an
+ * OFB one the last block may not be a multiple of the block size.
+ */
+public class BufferedBlockCipher
+{
+    protected byte[]        buf;
+    protected int           bufOff;
+
+    protected boolean       forEncryption;
+    protected BlockCipher   cipher;
+
+    protected boolean       partialBlockOkay;
+    protected boolean       pgpCFB;
+
+    /**
+     * constructor for subclasses
+     */
+    protected BufferedBlockCipher()
+    {
+    }
+
+    /**
+     * Create a buffered block cipher without padding.
+     *
+     * @param cipher the underlying block cipher this buffering object wraps.
+     */
+    public BufferedBlockCipher(
+        BlockCipher     cipher)
+    {
+        this.cipher = cipher;
+
+        buf = new byte[cipher.getBlockSize()];
+        bufOff = 0;
+
+        //
+        // check if we can handle partial blocks on doFinal.
+        //
+        String  name = cipher.getAlgorithmName();
+        int     idx = name.indexOf('/') + 1;
+
+        pgpCFB = (idx > 0 && name.startsWith("PGP", idx));
+
+        if (pgpCFB)
+        {
+            partialBlockOkay = true;
+        }
+        else
+        {
+            partialBlockOkay = (idx > 0 && (name.startsWith("CFB", idx) || name.startsWith("OFB", idx) || name.startsWith("OpenPGP", idx) || name.startsWith("SIC", idx) || name.startsWith("GCTR", idx)));
+        }
+    }
+
+    /**
+     * return the cipher this object wraps.
+     *
+     * @return the cipher this object wraps.
+     */
+    public BlockCipher getUnderlyingCipher()
+    {
+        return cipher;
+    }
+
+    /**
+     * initialise the cipher.
+     *
+     * @param forEncryption if true the cipher is initialised for
+     *  encryption, if false for decryption.
+     * @param params the key and other data required by the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean             forEncryption,
+        CipherParameters    params)
+        throws IllegalArgumentException
+    {
+        this.forEncryption = forEncryption;
+
+        reset();
+
+        cipher.init(forEncryption, params);
+    }
+
+    /**
+     * return the blocksize for the underlying cipher.
+     *
+     * @return the blocksize for the underlying cipher.
+     */
+    public int getBlockSize()
+    {
+        return cipher.getBlockSize();
+    }
+
+    /**
+     * return the size of the output buffer required for an update 
+     * an input of len bytes.
+     *
+     * @param len the length of the input.
+     * @return the space required to accommodate a call to update
+     * with len bytes of input.
+     */
+    public int getUpdateOutputSize(
+        int len)
+    {
+        int total       = len + bufOff;
+        int leftOver;
+
+        if (pgpCFB)
+        {
+            leftOver    = total % buf.length - (cipher.getBlockSize() + 2);
+        }
+        else
+        {
+            leftOver    = total % buf.length;
+        }
+
+        return total - leftOver;
+    }
+
+    /**
+     * return the size of the output buffer required for an update plus a
+     * doFinal with an input of len bytes.
+     *
+     * @param len the length of the input.
+     * @return the space required to accommodate a call to update and doFinal
+     * with len bytes of input.
+     */
+    public int getOutputSize(
+        int len)
+    {
+        int total       = len + bufOff;
+        int leftOver;
+
+        if (pgpCFB)
+        {
+            leftOver    = total % buf.length - (cipher.getBlockSize() + 2);
+        }
+        else
+        {
+            leftOver    = total % buf.length;
+            if (leftOver == 0)
+            {
+                return total;
+            }
+        }
+
+        return total - leftOver + buf.length;
+    }
+
+    /**
+     * process a single byte, producing an output block if neccessary.
+     *
+     * @param in the input byte.
+     * @param out the space for any output that might be produced.
+     * @param outOff the offset from which the output will be copied.
+     * @return the number of output bytes copied to out.
+     * @exception DataLengthException if there isn't enough space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     */
+    public int processByte(
+        byte        in,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        int         resultLen = 0;
+
+        buf[bufOff++] = in;
+
+        if (bufOff == buf.length)
+        {
+            resultLen = cipher.processBlock(buf, 0, out, outOff);
+            bufOff = 0;
+        }
+
+        return resultLen;
+    }
+
+    /**
+     * process an array of bytes, producing output if necessary.
+     *
+     * @param in the input byte array.
+     * @param inOff the offset at which the input data starts.
+     * @param len the number of bytes to be copied out of the input array.
+     * @param out the space for any output that might be produced.
+     * @param outOff the offset from which the output will be copied.
+     * @return the number of output bytes copied to out.
+     * @exception DataLengthException if there isn't enough space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     */
+    public int processBytes(
+        byte[]      in,
+        int         inOff,
+        int         len,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        if (len < 0)
+        {
+            throw new IllegalArgumentException("Can't have a negative input length!");
+        }
+
+        int blockSize   = getBlockSize();
+        int length      = getUpdateOutputSize(len);
+        
+        if (length > 0)
+        {
+            if ((outOff + length) > out.length)
+            {
+                throw new DataLengthException("output buffer too short");
+            }
+        }
+
+        int resultLen = 0;
+        int gapLen = buf.length - bufOff;
+
+        if (len > gapLen)
+        {
+            System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+            resultLen += cipher.processBlock(buf, 0, out, outOff);
+
+            bufOff = 0;
+            len -= gapLen;
+            inOff += gapLen;
+
+            while (len > buf.length)
+            {
+                resultLen += cipher.processBlock(in, inOff, out, outOff + resultLen);
+
+                len -= blockSize;
+                inOff += blockSize;
+            }
+        }
+
+        System.arraycopy(in, inOff, buf, bufOff, len);
+
+        bufOff += len;
+
+        if (bufOff == buf.length)
+        {
+            resultLen += cipher.processBlock(buf, 0, out, outOff + resultLen);
+            bufOff = 0;
+        }
+
+        return resultLen;
+    }
+
+    /**
+     * Process the last block in the buffer.
+     *
+     * @param out the array the block currently being held is copied into.
+     * @param outOff the offset at which the copying starts.
+     * @return the number of output bytes copied to out.
+     * @exception DataLengthException if there is insufficient space in out for
+     * the output, or the input is not block size aligned and should be.
+     * @exception IllegalStateException if the underlying cipher is not
+     * initialised.
+     * @exception InvalidCipherTextException if padding is expected and not found.
+     * @exception DataLengthException if the input is not block size
+     * aligned.
+     */
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+        throws DataLengthException, IllegalStateException, InvalidCipherTextException
+    {
+        int resultLen = 0;
+
+        if (outOff + bufOff > out.length)
+        {
+            throw new DataLengthException("output buffer too short for doFinal()");
+        }
+
+        if (bufOff != 0 && partialBlockOkay)
+        {
+            cipher.processBlock(buf, 0, buf, 0);
+            resultLen = bufOff;
+            bufOff = 0;
+            System.arraycopy(buf, 0, out, outOff, resultLen);
+        }
+        else if (bufOff != 0)
+        {
+            throw new DataLengthException("data not block size aligned");
+        }
+
+        reset();
+
+        return resultLen;
+    }
+
+    /**
+     * Reset the buffer and cipher. After resetting the object is in the same
+     * state as it was after the last init (if there was one).
+     */
+    public void reset()
+    {
+        //
+        // clean the buffer.
+        //
+        for (int i = 0; i < buf.length; i++)
+        {
+            buf[i] = 0;
+        }
+
+        bufOff = 0;
+
+        //
+        // reset the underlying cipher.
+        //
+        cipher.reset();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/CipherKeyGenerator.java b/libcore/security/src/main/java/org/bouncycastle/crypto/CipherKeyGenerator.java
new file mode 100644
index 0000000..451f8e8
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/CipherKeyGenerator.java
@@ -0,0 +1,38 @@
+package org.bouncycastle.crypto;
+
+import java.security.SecureRandom;
+
+/**
+ * The base class for symmetric, or secret, cipher key generators.
+ */
+public class CipherKeyGenerator
+{
+    protected SecureRandom  random;
+    protected int           strength;
+
+    /**
+     * initialise the key generator.
+     *
+     * @param param the parameters to be used for key generation
+     */
+    public void init(
+        KeyGenerationParameters param)
+    {
+        this.random = param.getRandom();
+        this.strength = (param.getStrength() + 7) / 8;
+    }
+
+    /**
+     * generate a secret key.
+     *
+     * @return a byte array containing the key value.
+     */
+    public byte[] generateKey()
+    {
+        byte[]  key = new byte[strength];
+
+        random.nextBytes(key);
+
+        return key;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/CipherParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/CipherParameters.java
new file mode 100644
index 0000000..5be8730
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/CipherParameters.java
@@ -0,0 +1,8 @@
+package org.bouncycastle.crypto;
+
+/**
+ * all parameter classes implement this.
+ */
+public interface CipherParameters
+{
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/CryptoException.java b/libcore/security/src/main/java/org/bouncycastle/crypto/CryptoException.java
new file mode 100644
index 0000000..dc4a8df
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/CryptoException.java
@@ -0,0 +1,26 @@
+package org.bouncycastle.crypto;
+
+/**
+ * the foundation class for the hard exceptions thrown by the crypto packages.
+ */
+public class CryptoException 
+    extends Exception
+{
+    /**
+     * base constructor.
+     */
+    public CryptoException()
+    {
+    }
+
+    /**
+     * create a CryptoException with the given message.
+     *
+     * @param message the message to be carried with the exception.
+     */
+    public CryptoException(
+        String  message)
+    {
+        super(message);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/DSA.java b/libcore/security/src/main/java/org/bouncycastle/crypto/DSA.java
new file mode 100644
index 0000000..1f58476
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/DSA.java
@@ -0,0 +1,36 @@
+package org.bouncycastle.crypto;
+
+import java.math.BigInteger;
+
+/**
+ * interface for classes implementing algorithms modeled similar to the Digital Signature Alorithm.
+ */
+public interface DSA
+{
+    /**
+     * initialise the signer for signature generation or signature
+     * verification.
+     *
+     * @param forSigning true if we are generating a signature, false
+     * otherwise.
+     * @param param key parameters for signature generation.
+     */
+    public void init(boolean forSigning, CipherParameters param);
+
+    /**
+     * sign the passed in message (usually the output of a hash function).
+     *
+     * @param message the message to be signed.
+     * @return two big integers representing the r and s values respectively.
+     */
+    public BigInteger[] generateSignature(byte[] message);
+
+    /**
+     * verify the message message against the signature values r and s.
+     *
+     * @param message the message that was supposed to have been signed.
+     * @param r the r signature value.
+     * @param s the s signature value.
+     */
+    public boolean verifySignature(byte[] message, BigInteger  r, BigInteger s);
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/DataLengthException.java b/libcore/security/src/main/java/org/bouncycastle/crypto/DataLengthException.java
new file mode 100644
index 0000000..fbf047c
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/DataLengthException.java
@@ -0,0 +1,29 @@
+package org.bouncycastle.crypto;
+
+/**
+ * this exception is thrown if a buffer that is meant to have output
+ * copied into it turns out to be too short, or if we've been given 
+ * insufficient input. In general this exception will get thrown rather
+ * than an ArrayOutOfBounds exception.
+ */
+public class DataLengthException 
+    extends RuntimeCryptoException
+{
+    /**
+     * base constructor.
+     */
+    public DataLengthException()
+    {
+    }
+
+    /**
+     * create a DataLengthException with the given message.
+     *
+     * @param message the message to be carried with the exception.
+     */
+    public DataLengthException(
+        String  message)
+    {
+        super(message);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/DerivationFunction.java b/libcore/security/src/main/java/org/bouncycastle/crypto/DerivationFunction.java
new file mode 100644
index 0000000..ef6e29e
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/DerivationFunction.java
@@ -0,0 +1,17 @@
+package org.bouncycastle.crypto;
+
+/**
+ * base interface for general purpose byte derivation functions.
+ */
+public interface DerivationFunction
+{
+    public void init(DerivationParameters param);
+
+    /**
+     * return the message digest used as the basis for the function
+     */
+    public Digest getDigest();
+
+    public int generateBytes(byte[] out, int outOff, int len)
+        throws DataLengthException, IllegalArgumentException;
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/DerivationParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/DerivationParameters.java
new file mode 100644
index 0000000..e11eb86
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/DerivationParameters.java
@@ -0,0 +1,8 @@
+package org.bouncycastle.crypto;
+
+/**
+ * Parameters for key/byte stream derivation classes
+ */
+public interface DerivationParameters
+{
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/Digest.java b/libcore/security/src/main/java/org/bouncycastle/crypto/Digest.java
new file mode 100644
index 0000000..f44fad0
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/Digest.java
@@ -0,0 +1,51 @@
+package org.bouncycastle.crypto;
+
+/**
+ * interface that a message digest conforms to.
+ */
+public interface Digest
+{
+    /**
+     * return the algorithm name
+     *
+     * @return the algorithm name
+     */
+    public String getAlgorithmName();
+
+    /**
+     * return the size, in bytes, of the digest produced by this message digest.
+     *
+     * @return the size, in bytes, of the digest produced by this message digest.
+     */
+    public int getDigestSize();
+
+    /**
+     * update the message digest with a single byte.
+     *
+     * @param in the input byte to be entered.
+     */
+    public void update(byte in);
+
+    /**
+     * update the message digest with a block of bytes.
+     *
+     * @param in the byte array containing the data.
+     * @param inOff the offset into the byte array where the data starts.
+     * @param len the length of the data.
+     */
+    public void update(byte[] in, int inOff, int len);
+
+    /**
+     * close the digest, producing the final digest value. The doFinal
+     * call leaves the digest reset.
+     *
+     * @param out the array the digest is to be copied into.
+     * @param outOff the offset into the out array the digest is to start at.
+     */
+    public int doFinal(byte[] out, int outOff);
+
+    /**
+     * reset the digest back to it's initial state.
+     */
+    public void reset();
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/ExtendedDigest.java b/libcore/security/src/main/java/org/bouncycastle/crypto/ExtendedDigest.java
new file mode 100644
index 0000000..c5e9e8b
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/ExtendedDigest.java
@@ -0,0 +1,13 @@
+package org.bouncycastle.crypto;
+
+public interface ExtendedDigest 
+    extends Digest
+{
+    /**
+     * Return the size in bytes of the internal buffer the digest applies it's compression
+     * function to.
+     * 
+     * @return byte length of the digests internal buffer.
+     */
+    public int getByteLength();
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/InvalidCipherTextException.java b/libcore/security/src/main/java/org/bouncycastle/crypto/InvalidCipherTextException.java
new file mode 100644
index 0000000..59e4b26
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/InvalidCipherTextException.java
@@ -0,0 +1,27 @@
+package org.bouncycastle.crypto;
+
+/**
+ * this exception is thrown whenever we find something we don't expect in a
+ * message.
+ */
+public class InvalidCipherTextException 
+    extends CryptoException
+{
+    /**
+     * base constructor.
+     */
+    public InvalidCipherTextException()
+    {
+    }
+
+    /**
+     * create a InvalidCipherTextException with the given message.
+     *
+     * @param message the message to be carried with the exception.
+     */
+    public InvalidCipherTextException(
+        String  message)
+    {
+        super(message);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/KeyGenerationParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/KeyGenerationParameters.java
new file mode 100644
index 0000000..9a63522
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/KeyGenerationParameters.java
@@ -0,0 +1,48 @@
+package org.bouncycastle.crypto;
+
+import java.security.SecureRandom;
+
+/**
+ * The base class for parameters to key generators.
+ */
+public class KeyGenerationParameters
+{
+    private SecureRandom    random;
+    private int             strength;
+
+    /**
+     * initialise the generator with a source of randomness
+     * and a strength (in bits).
+     *
+     * @param random the random byte source.
+     * @param strength the size, in bits, of the keys we want to produce.
+     */
+    public KeyGenerationParameters(
+        SecureRandom    random,
+        int             strength)
+    {
+        this.random = random;
+        this.strength = strength;
+    }
+
+    /**
+     * return the random source associated with this
+     * generator.
+     *
+     * @return the generators random source.
+     */
+    public SecureRandom getRandom()
+    {
+        return random;
+    }
+
+    /**
+     * return the bit strength for keys produced by this generator,
+     *
+     * @return the strength of the keys this generator produces (in bits).
+     */
+    public int getStrength()
+    {
+        return strength;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/Mac.java b/libcore/security/src/main/java/org/bouncycastle/crypto/Mac.java
new file mode 100644
index 0000000..8c122c8
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/Mac.java
@@ -0,0 +1,71 @@
+package org.bouncycastle.crypto;
+
+
+/**
+ * The base interface for implementations of message authentication codes (MACs).
+ */
+public interface Mac
+{
+    /**
+     * Initialise the MAC.
+     *
+     * @param params the key and other data required by the MAC.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(CipherParameters params)
+        throws IllegalArgumentException;
+
+    /**
+     * Return the name of the algorithm the MAC implements.
+     *
+     * @return the name of the algorithm the MAC implements.
+     */
+    public String getAlgorithmName();
+
+    /**
+     * Return the block size for this MAC (in bytes).
+     *
+     * @return the block size for this MAC in bytes.
+     */
+    public int getMacSize();
+
+    /**
+     * add a single byte to the mac for processing.
+     *
+     * @param in the byte to be processed.
+     * @exception IllegalStateException if the MAC is not initialised.
+     */
+    public void update(byte in)
+        throws IllegalStateException;
+
+    /**
+     * @param in the array containing the input.
+     * @param inOff the index in the array the data begins at.
+     * @param len the length of the input starting at inOff.
+     * @exception IllegalStateException if the MAC is not initialised.
+     * @exception DataLengthException if there isn't enough data in in.
+     */
+    public void update(byte[] in, int inOff, int len)
+        throws DataLengthException, IllegalStateException;
+
+    /**
+     * Compute the final statge of the MAC writing the output to the out
+     * parameter.
+     * <p>
+     * doFinal leaves the MAC in the same state it was after the last init.
+     *
+     * @param out the array the MAC is to be output to.
+     * @param outOff the offset into the out buffer the output is to start at.
+     * @exception DataLengthException if there isn't enough space in out.
+     * @exception IllegalStateException if the MAC is not initialised.
+     */
+    public int doFinal(byte[] out, int outOff)
+        throws DataLengthException, IllegalStateException;
+
+    /**
+     * Reset the MAC. At the end of resetting the MAC should be in the
+     * in the same state it was after the last init (if there was one).
+     */
+    public void reset();
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/PBEParametersGenerator.java b/libcore/security/src/main/java/org/bouncycastle/crypto/PBEParametersGenerator.java
new file mode 100644
index 0000000..12000aa
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/PBEParametersGenerator.java
@@ -0,0 +1,142 @@
+package org.bouncycastle.crypto;
+
+/**
+ * super class for all Password Based Encryption (PBE) parameter generator classes.
+ */
+public abstract class PBEParametersGenerator
+{
+    protected byte[]  password;
+    protected byte[]  salt;
+    protected int     iterationCount;
+
+    /**
+     * base constructor.
+     */
+    protected PBEParametersGenerator()
+    {
+    }
+
+    /**
+     * initialise the PBE generator.
+     *
+     * @param password the password converted into bytes (see below).
+     * @param salt the salt to be mixed with the password.
+     * @param iterationCount the number of iterations the "mixing" function
+     * is to be applied for.
+     */
+    public void init(
+        byte[]  password,
+        byte[]  salt,
+        int     iterationCount)
+    {
+        this.password = password;
+        this.salt = salt;
+        this.iterationCount = iterationCount;
+    }
+
+    /**
+     * return the password byte array.
+     *
+     * @return the password byte array.
+     */
+    public byte[] getPassword()
+    {
+        return password;
+    }
+
+    /**
+     * return the salt byte array.
+     *
+     * @return the salt byte array.
+     */
+    public byte[] getSalt()
+    {
+        return salt;
+    }
+
+    /**
+     * return the iteration count.
+     *
+     * @return the iteration count.
+     */
+    public int getIterationCount()
+    {
+        return iterationCount;
+    }
+
+    /**
+     * generate derived parameters for a key of length keySize.
+     *
+     * @param keySize the length, in bits, of the key required.
+     * @return a parameters object representing a key.
+     */
+    public abstract CipherParameters generateDerivedParameters(int keySize);
+
+    /**
+     * generate derived parameters for a key of length keySize, and
+     * an initialisation vector (IV) of length ivSize.
+     *
+     * @param keySize the length, in bits, of the key required.
+     * @param ivSize the length, in bits, of the iv required.
+     * @return a parameters object representing a key and an IV.
+     */
+    public abstract CipherParameters generateDerivedParameters(int keySize, int ivSize);
+
+    /**
+     * generate derived parameters for a key of length keySize, specifically
+     * for use with a MAC.
+     *
+     * @param keySize the length, in bits, of the key required.
+     * @return a parameters object representing a key.
+     */
+    public abstract CipherParameters generateDerivedMacParameters(int keySize);
+
+    /**
+     * converts a password to a byte array according to the scheme in
+     * PKCS5 (ascii, no padding)
+     *
+     * @param password a character array reqpresenting the password.
+     * @return a byte array representing the password.
+     */
+    public static byte[] PKCS5PasswordToBytes(
+        char[]  password)
+    {
+        byte[]  bytes = new byte[password.length];
+
+        for (int i = 0; i != bytes.length; i++)
+        {
+            bytes[i] = (byte)password[i];
+        }
+
+        return bytes;
+    }
+
+    /**
+     * converts a password to a byte array according to the scheme in
+     * PKCS12 (unicode, big endian, 2 zero pad bytes at the end).
+     *
+     * @param password a character array reqpresenting the password.
+     * @return a byte array representing the password.
+     */
+    public static byte[] PKCS12PasswordToBytes(
+        char[]  password)
+    {
+        if (password.length > 0)
+        {
+                                       // +1 for extra 2 pad bytes.
+            byte[]  bytes = new byte[(password.length + 1) * 2];
+
+            for (int i = 0; i != password.length; i ++)
+            {
+                bytes[i * 2] = (byte)(password[i] >>> 8);
+                bytes[i * 2 + 1] = (byte)password[i];
+            }
+
+            return bytes;
+        }
+        else
+        {
+            return new byte[0];
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/RuntimeCryptoException.java b/libcore/security/src/main/java/org/bouncycastle/crypto/RuntimeCryptoException.java
new file mode 100644
index 0000000..c157202
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/RuntimeCryptoException.java
@@ -0,0 +1,26 @@
+package org.bouncycastle.crypto;
+
+/**
+ * the foundation class for the exceptions thrown by the crypto packages.
+ */
+public class RuntimeCryptoException 
+    extends RuntimeException
+{
+    /**
+     * base constructor.
+     */
+    public RuntimeCryptoException()
+    {
+    }
+
+    /**
+     * create a RuntimeCryptoException with the given message.
+     *
+     * @param message the message to be carried with the exception.
+     */
+    public RuntimeCryptoException(
+        String  message)
+    {
+        super(message);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/Signer.java b/libcore/security/src/main/java/org/bouncycastle/crypto/Signer.java
new file mode 100644
index 0000000..357b0da
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/Signer.java
@@ -0,0 +1,43 @@
+package org.bouncycastle.crypto;
+
+/**
+ * Generic signer interface for hash based and message recovery signers.
+ */
+public interface Signer 
+{
+    /**
+     * Initialise the signer for signing or verification.
+     * 
+     * @param forSigning true if for signing, false otherwise
+     * @param param necessary parameters.
+     */
+    public void init(boolean forSigning, CipherParameters param);
+
+    /**
+     * update the internal digest with the byte b
+     */
+    public void update(byte b);
+
+    /**
+     * update the internal digest with the byte array in
+     */
+    public void update(byte[] in, int off, int len);
+
+    /**
+     * generate a signature for the message we've been loaded with using
+     * the key we were initialised with.
+     */
+    public byte[] generateSignature()
+        throws CryptoException, DataLengthException;
+
+    /**
+     * return true if the internal state represents the signature described
+     * in the passed in array.
+     */
+    public boolean verifySignature(byte[] signature);
+    
+    /**
+     * reset the internal state
+     */
+    public void reset();
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/SignerWithRecovery.java b/libcore/security/src/main/java/org/bouncycastle/crypto/SignerWithRecovery.java
new file mode 100644
index 0000000..5a1e204
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/SignerWithRecovery.java
@@ -0,0 +1,23 @@
+package org.bouncycastle.crypto;
+
+/**
+ * Signer with message recovery.
+ */
+public interface SignerWithRecovery 
+    extends Signer
+{
+    /**
+     * Returns true if the signer has recovered the full message as
+     * part of signature verification.
+     * 
+     * @return true if full message recovered.
+     */
+    public boolean hasFullMessage();
+    
+    /**
+     * Returns a reference to what message was recovered (if any).
+     * 
+     * @return full/partial message, null if nothing.
+     */
+    public byte[] getRecoveredMessage();
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/StreamBlockCipher.java b/libcore/security/src/main/java/org/bouncycastle/crypto/StreamBlockCipher.java
new file mode 100644
index 0000000..8fdd232
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/StreamBlockCipher.java
@@ -0,0 +1,108 @@
+package org.bouncycastle.crypto;
+
+/**
+ * a wrapper for block ciphers with a single byte block size, so that they
+ * can be treated like stream ciphers.
+ */
+public class StreamBlockCipher
+    implements StreamCipher
+{
+    private BlockCipher  cipher;
+
+    private byte[]  oneByte = new byte[1];
+
+    /**
+     * basic constructor.
+     *
+     * @param cipher the block cipher to be wrapped.
+     * @exception IllegalArgumentException if the cipher has a block size other than
+     * one.
+     */
+    public StreamBlockCipher(
+        BlockCipher cipher)
+    {
+        if (cipher.getBlockSize() != 1)
+        {
+            throw new IllegalArgumentException("block cipher block size != 1.");
+        }
+
+        this.cipher = cipher;
+    }
+
+    /**
+     * initialise the underlying cipher.
+     *
+     * @param forEncryption true if we are setting up for encryption, false otherwise.
+     * @param params the necessary parameters for the underlying cipher to be initialised.
+     */
+    public void init(
+        boolean forEncryption,
+        CipherParameters params)
+    {
+        cipher.init(forEncryption, params);
+    }
+
+    /**
+     * return the name of the algorithm we are wrapping.
+     *
+     * @return the name of the algorithm we are wrapping.
+     */
+    public String getAlgorithmName()
+    {
+        return cipher.getAlgorithmName();
+    }
+
+    /**
+     * encrypt/decrypt a single byte returning the result.
+     *
+     * @param in the byte to be processed.
+     * @return the result of processing the input byte.
+     */
+    public byte returnByte(
+        byte    in)
+    {
+        oneByte[0] = in;
+
+        cipher.processBlock(oneByte, 0, oneByte, 0);
+
+        return oneByte[0];
+    }
+
+    /**
+     * process a block of bytes from in putting the result into out.
+     * 
+     * @param in the input byte array.
+     * @param inOff the offset into the in array where the data to be processed starts.
+     * @param len the number of bytes to be processed.
+     * @param out the output buffer the processed bytes go into.   
+     * @param outOff the offset into the output byte array the processed data stars at.
+     * @exception DataLengthException if the output buffer is too small.
+     */
+    public void processBytes(
+        byte[]  in,
+        int     inOff,
+        int     len,
+        byte[]  out,
+        int     outOff)
+        throws DataLengthException
+    {
+        if (outOff + len > out.length)
+        {
+            throw new DataLengthException("output buffer too small in processBytes()");
+        }
+
+        for (int i = 0; i != len; i++)
+        {
+                cipher.processBlock(in, inOff + i, out, outOff + i);
+        }
+    }
+
+    /**
+     * reset the underlying cipher. This leaves it in the same state
+     * it was at after the last init (if there was one).
+     */
+    public void reset()
+    {
+        cipher.reset();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/StreamCipher.java b/libcore/security/src/main/java/org/bouncycastle/crypto/StreamCipher.java
new file mode 100644
index 0000000..afa6296
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/StreamCipher.java
@@ -0,0 +1,53 @@
+package org.bouncycastle.crypto;
+
+/**
+ * the interface stream ciphers conform to.
+ */
+public interface StreamCipher
+{
+    /**
+     * Initialise the cipher.
+     *
+     * @param forEncryption if true the cipher is initialised for
+     *  encryption, if false for decryption.
+     * @param params the key and other data required by the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(boolean forEncryption, CipherParameters params)
+        throws IllegalArgumentException;
+
+    /**
+     * Return the name of the algorithm the cipher implements.
+     *
+     * @return the name of the algorithm the cipher implements.
+     */
+    public String getAlgorithmName();
+
+    /**
+     * encrypt/decrypt a single byte returning the result.
+     *
+     * @param in the byte to be processed.
+     * @return the result of processing the input byte.
+     */
+    public byte returnByte(byte in);
+
+    /**
+     * process a block of bytes from in putting the result into out.
+     *
+     * @param in the input byte array.
+     * @param inOff the offset into the in array where the data to be processed starts.
+     * @param len the number of bytes to be processed.
+     * @param out the output buffer the processed bytes go into.
+     * @param outOff the offset into the output byte array the processed data stars at.
+     * @exception DataLengthException if the output buffer is too small.
+     */
+    public void processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
+        throws DataLengthException;
+
+    /**
+     * reset the cipher. This leaves it in the same state
+     * it was at after the last init (if there was one).
+     */
+    public void reset();
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/Wrapper.java b/libcore/security/src/main/java/org/bouncycastle/crypto/Wrapper.java
new file mode 100644
index 0000000..3956a6f
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/Wrapper.java
@@ -0,0 +1,18 @@
+package org.bouncycastle.crypto;
+
+public interface Wrapper
+{
+    public void init(boolean forWrapping, CipherParameters param);
+
+    /**
+     * Return the name of the algorithm the wrapper implements.
+     *
+     * @return the name of the algorithm the wrapper implements.
+     */
+    public String getAlgorithmName();
+
+    public byte[] wrap(byte[] in, int inOff, int inLen);
+
+    public byte[] unwrap(byte[] in, int inOff, int inLen)
+        throws InvalidCipherTextException;
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/agreement/DHAgreement.java b/libcore/security/src/main/java/org/bouncycastle/crypto/agreement/DHAgreement.java
new file mode 100644
index 0000000..2b27feb
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/agreement/DHAgreement.java
@@ -0,0 +1,86 @@
+package org.bouncycastle.crypto.agreement;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.params.DHParameters;
+import org.bouncycastle.crypto.params.DHPublicKeyParameters;
+import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+
+/**
+ * a Diffie-Hellman key exchange engine.
+ * <p>
+ * note: This uses MTI/A0 key agreement in order to make the key agreement
+ * secure against passive attacks. If you're doing Diffie-Hellman and both
+ * parties have long term public keys you should look at using this. For
+ * further information have a look at RFC 2631.
+ * <p>
+ * It's possible to extend this to more than two parties as well, for the moment
+ * that is left as an exercise for the reader.
+ */
+public class DHAgreement
+{
+    private DHPrivateKeyParameters  key;
+    private DHParameters            dhParams;
+    private BigInteger              privateValue;
+    private SecureRandom            random;
+
+    public void init(
+        CipherParameters    param)
+    {
+        AsymmetricKeyParameter  kParam;
+
+        if (param instanceof ParametersWithRandom)
+        {
+            ParametersWithRandom    rParam = (ParametersWithRandom)param;
+
+            this.random = rParam.getRandom();
+            kParam = (AsymmetricKeyParameter)rParam.getParameters();
+        }
+        else
+        {
+            this.random = new SecureRandom();
+            kParam = (AsymmetricKeyParameter)param;
+        }
+
+        
+        if (!(kParam instanceof DHPrivateKeyParameters))
+        {
+            throw new IllegalArgumentException("DHEngine expects DHPrivateKeyParameters");
+        }
+
+        this.key = (DHPrivateKeyParameters)kParam;
+        this.dhParams = key.getParameters();
+    }
+
+    /**
+     * calculate our initial message.
+     */
+    public BigInteger calculateMessage()
+    {
+        this.privateValue = new BigInteger(
+                                    dhParams.getP().bitLength() - 1, 0, random);
+
+        return dhParams.getG().modPow(privateValue, dhParams.getP());
+    }
+
+    /**
+     * given a message from a given party and the coresponding public key
+     * calculate the next message in the agreement sequence. In this case
+     * this will represent the shared secret.
+     */
+    public BigInteger calculateAgreement(
+        DHPublicKeyParameters   pub,
+        BigInteger              message)
+    {
+        if (!pub.getParameters().equals(dhParams))
+        {
+            throw new IllegalArgumentException("Diffie-Hellman public key has wrong parameters.");
+        }
+
+        return message.modPow(key.getX(), dhParams.getP()).multiply(pub.getY().modPow(privateValue, dhParams.getP())).mod(dhParams.getP());
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java b/libcore/security/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java
new file mode 100644
index 0000000..1a39de3
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java
@@ -0,0 +1,72 @@
+package org.bouncycastle.crypto.agreement;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.BasicAgreement;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.params.DHParameters;
+import org.bouncycastle.crypto.params.DHPublicKeyParameters;
+import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+
+/**
+ * a Diffie-Hellman key agreement class.
+ * <p>
+ * note: This is only the basic algorithm, it doesn't take advantage of
+ * long term public keys if they are available. See the DHAgreement class
+ * for a "better" implementation.
+ */
+public class DHBasicAgreement
+    implements BasicAgreement
+{
+    private DHPrivateKeyParameters  key;
+    private DHParameters            dhParams;
+    private SecureRandom            random;
+
+    public void init(
+        CipherParameters    param)
+    {
+        AsymmetricKeyParameter  kParam;
+
+        if (param instanceof ParametersWithRandom)
+        {
+            ParametersWithRandom    rParam = (ParametersWithRandom)param;
+
+            this.random = rParam.getRandom();
+            kParam = (AsymmetricKeyParameter)rParam.getParameters();
+        }
+        else
+        {
+            this.random = new SecureRandom();
+            kParam = (AsymmetricKeyParameter)param;
+        }
+
+        
+        if (!(kParam instanceof DHPrivateKeyParameters))
+        {
+            throw new IllegalArgumentException("DHEngine expects DHPrivateKeyParameters");
+        }
+
+        this.key = (DHPrivateKeyParameters)kParam;
+        this.dhParams = key.getParameters();
+    }
+
+    /**
+     * given a short term public key from a given party calculate the next
+     * message in the agreement sequence. 
+     */
+    public BigInteger calculateAgreement(
+        CipherParameters   pubKey)
+    {
+        DHPublicKeyParameters   pub = (DHPublicKeyParameters)pubKey;
+
+        if (!pub.getParameters().equals(dhParams))
+        {
+            throw new IllegalArgumentException("Diffie-Hellman public key has wrong parameters.");
+        }
+
+        return pub.getY().modPow(key.getX(), dhParams.getP());
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java b/libcore/security/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java
new file mode 100644
index 0000000..f2c9967
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java
@@ -0,0 +1,135 @@
+package org.bouncycastle.crypto.digests;
+
+import org.bouncycastle.crypto.ExtendedDigest;
+
+/**
+ * base implementation of MD4 family style digest as outlined in
+ * "Handbook of Applied Cryptography", pages 344 - 347.
+ */
+public abstract class GeneralDigest
+    implements ExtendedDigest
+{
+    private static final int BYTE_LENGTH = 64;
+    private byte[]  xBuf;
+    private int     xBufOff;
+
+    private long    byteCount;
+
+    /**
+     * Standard constructor
+     */
+    protected GeneralDigest()
+    {
+        xBuf = new byte[4];
+        xBufOff = 0;
+    }
+
+    /**
+     * Copy constructor.  We are using copy constructors in place
+     * of the Object.clone() interface as this interface is not
+     * supported by J2ME.
+     */
+    protected GeneralDigest(GeneralDigest t)
+    {
+        xBuf = new byte[t.xBuf.length];
+        System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length);
+
+        xBufOff = t.xBufOff;
+        byteCount = t.byteCount;
+    }
+
+    public void update(
+        byte in)
+    {
+        xBuf[xBufOff++] = in;
+
+        if (xBufOff == xBuf.length)
+        {
+            processWord(xBuf, 0);
+            xBufOff = 0;
+        }
+
+        byteCount++;
+    }
+
+    public void update(
+        byte[]  in,
+        int     inOff,
+        int     len)
+    {
+        //
+        // fill the current word
+        //
+        while ((xBufOff != 0) && (len > 0))
+        {
+            update(in[inOff]);
+
+            inOff++;
+            len--;
+        }
+
+        //
+        // process whole words.
+        //
+        while (len > xBuf.length)
+        {
+            processWord(in, inOff);
+
+            inOff += xBuf.length;
+            len -= xBuf.length;
+            byteCount += xBuf.length;
+        }
+
+        //
+        // load in the remainder.
+        //
+        while (len > 0)
+        {
+            update(in[inOff]);
+
+            inOff++;
+            len--;
+        }
+    }
+
+    public void finish()
+    {
+        long    bitLength = (byteCount << 3);
+
+        //
+        // add the pad bytes.
+        //
+        update((byte)128);
+
+        while (xBufOff != 0)
+        {
+            update((byte)0);
+        }
+
+        processLength(bitLength);
+
+        processBlock();
+    }
+
+    public void reset()
+    {
+        byteCount = 0;
+
+        xBufOff = 0;
+        for (int i = 0; i < xBuf.length; i++)
+        {
+            xBuf[i] = 0;
+        }
+    }
+
+    public int getByteLength()
+    {
+        return BYTE_LENGTH;
+    }
+    
+    protected abstract void processWord(byte[] in, int inOff);
+
+    protected abstract void processLength(long bitLength);
+
+    protected abstract void processBlock();
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/digests/LongDigest.java b/libcore/security/src/main/java/org/bouncycastle/crypto/digests/LongDigest.java
new file mode 100644
index 0000000..23af605
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/digests/LongDigest.java
@@ -0,0 +1,375 @@
+package org.bouncycastle.crypto.digests;
+
+import org.bouncycastle.crypto.ExtendedDigest;
+
+/**
+ * Base class for SHA-384 and SHA-512.
+ */
+public abstract class LongDigest
+    implements ExtendedDigest
+{
+    private static final int BYTE_LENGTH = 128;
+    
+    private byte[]  xBuf;
+    private int     xBufOff;
+
+    private long    byteCount1;
+    private long    byteCount2;
+
+    protected long    H1, H2, H3, H4, H5, H6, H7, H8;
+
+    private long[]  W = new long[80];
+    private int     wOff;
+
+    /**
+     * Constructor for variable length word
+     */
+    protected LongDigest()
+    {
+        xBuf = new byte[8];
+        xBufOff = 0;
+
+        reset();
+    }
+
+    /**
+     * Copy constructor.  We are using copy constructors in place
+     * of the Object.clone() interface as this interface is not
+     * supported by J2ME.
+     */
+    protected LongDigest(LongDigest t)
+    {
+        xBuf = new byte[t.xBuf.length];
+        System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length);
+
+        xBufOff = t.xBufOff;
+        byteCount1 = t.byteCount1;
+        byteCount2 = t.byteCount2;
+
+        H1 = t.H1;
+        H2 = t.H2;
+        H3 = t.H3;
+        H4 = t.H4;
+        H5 = t.H5;
+        H6 = t.H6;
+        H7 = t.H7;
+        H8 = t.H8;
+
+        System.arraycopy(t.W, 0, W, 0, t.W.length);
+        wOff = t.wOff;
+    }
+
+    public void update(
+        byte in)
+    {
+        xBuf[xBufOff++] = in;
+
+        if (xBufOff == xBuf.length)
+        {
+            processWord(xBuf, 0);
+            xBufOff = 0;
+        }
+
+        byteCount1++;
+    }
+
+    public void update(
+        byte[]  in,
+        int     inOff,
+        int     len)
+    {
+        //
+        // fill the current word
+        //
+        while ((xBufOff != 0) && (len > 0))
+        {
+            update(in[inOff]);
+
+            inOff++;
+            len--;
+        }
+
+        //
+        // process whole words.
+        //
+        while (len > xBuf.length)
+        {
+            processWord(in, inOff);
+
+            inOff += xBuf.length;
+            len -= xBuf.length;
+            byteCount1 += xBuf.length;
+        }
+
+        //
+        // load in the remainder.
+        //
+        while (len > 0)
+        {
+            update(in[inOff]);
+
+            inOff++;
+            len--;
+        }
+    }
+
+    public void finish()
+    {
+        adjustByteCounts();
+
+        long    lowBitLength = byteCount1 << 3;
+        long    hiBitLength = byteCount2;
+
+        //
+        // add the pad bytes.
+        //
+        update((byte)128);
+
+        while (xBufOff != 0)
+        {
+            update((byte)0);
+        }
+
+        processLength(lowBitLength, hiBitLength);
+
+        processBlock();
+    }
+
+    public void reset()
+    {
+        byteCount1 = 0;
+        byteCount2 = 0;
+
+        xBufOff = 0;
+        for (int i = 0; i < xBuf.length; i++)
+        {
+            xBuf[i] = 0;
+        }
+
+        wOff = 0;
+        for (int i = 0; i != W.length; i++)
+        {
+            W[i] = 0;
+        }
+    }
+
+    public int getByteLength()
+    {
+        return BYTE_LENGTH;
+    }
+    
+    protected void processWord(
+        byte[]  in,
+        int     inOff)
+    {
+        W[wOff++] = ((long)(in[inOff] & 0xff) << 56)
+                    | ((long)(in[inOff + 1] & 0xff) << 48)
+                    | ((long)(in[inOff + 2] & 0xff) << 40)
+                    | ((long)(in[inOff + 3] & 0xff) << 32)
+                    | ((long)(in[inOff + 4] & 0xff) << 24)
+                    | ((long)(in[inOff + 5] & 0xff) << 16)
+                    | ((long)(in[inOff + 6] & 0xff) << 8)
+                    | ((in[inOff + 7] & 0xff)); 
+
+        if (wOff == 16)
+        {
+            processBlock();
+        }
+    }
+
+    protected void unpackWord(
+        long    word,
+        byte[]  out,
+        int     outOff)
+    {
+        out[outOff]     = (byte)(word >>> 56);
+        out[outOff + 1] = (byte)(word >>> 48);
+        out[outOff + 2] = (byte)(word >>> 40);
+        out[outOff + 3] = (byte)(word >>> 32);
+        out[outOff + 4] = (byte)(word >>> 24);
+        out[outOff + 5] = (byte)(word >>> 16);
+        out[outOff + 6] = (byte)(word >>> 8);
+        out[outOff + 7] = (byte)word;
+    }
+
+    /**
+     * adjust the byte counts so that byteCount2 represents the
+     * upper long (less 3 bits) word of the byte count.
+     */
+    private void adjustByteCounts()
+    {
+        if (byteCount1 > 0x1fffffffffffffffL)
+        {
+            byteCount2 += (byteCount1 >>> 61);
+            byteCount1 &= 0x1fffffffffffffffL;
+        }
+    }
+
+    protected void processLength(
+        long    lowW,
+        long    hiW)
+    {
+        if (wOff > 14)
+        {
+            processBlock();
+        }
+
+        W[14] = hiW;
+        W[15] = lowW;
+    }
+
+    protected void processBlock()
+    {
+        adjustByteCounts();
+
+        //
+        // expand 16 word block into 80 word blocks.
+        //
+        for (int t = 16; t <= 79; t++)
+        {
+            W[t] = Sigma1(W[t - 2]) + W[t - 7] + Sigma0(W[t - 15]) + W[t - 16];
+        }
+
+        //
+        // set up working variables.
+        //
+        long     a = H1;
+        long     b = H2;
+        long     c = H3;
+        long     d = H4;
+        long     e = H5;
+        long     f = H6;
+        long     g = H7;
+        long     h = H8;
+
+        int t = 0;     
+        for(int i = 0; i < 10; i ++)
+        {
+          // t = 8 * i
+          h += Sum1(e) + Ch(e, f, g) + K[t] + W[t++];
+          d += h;
+          h += Sum0(a) + Maj(a, b, c);
+
+          // t = 8 * i + 1
+          g += Sum1(d) + Ch(d, e, f) + K[t] + W[t++];
+          c += g;
+          g += Sum0(h) + Maj(h, a, b);
+
+          // t = 8 * i + 2
+          f += Sum1(c) + Ch(c, d, e) + K[t] + W[t++];
+          b += f;
+          f += Sum0(g) + Maj(g, h, a);
+
+          // t = 8 * i + 3
+          e += Sum1(b) + Ch(b, c, d) + K[t] + W[t++];
+          a += e;
+          e += Sum0(f) + Maj(f, g, h);
+
+          // t = 8 * i + 4
+          d += Sum1(a) + Ch(a, b, c) + K[t] + W[t++];
+          h += d;
+          d += Sum0(e) + Maj(e, f, g);
+
+          // t = 8 * i + 5
+          c += Sum1(h) + Ch(h, a, b) + K[t] + W[t++];
+          g += c;
+          c += Sum0(d) + Maj(d, e, f);
+
+          // t = 8 * i + 6
+          b += Sum1(g) + Ch(g, h, a) + K[t] + W[t++];
+          f += b;
+          b += Sum0(c) + Maj(c, d, e);
+
+          // t = 8 * i + 7
+          a += Sum1(f) + Ch(f, g, h) + K[t] + W[t++];
+          e += a;
+          a += Sum0(b) + Maj(b, c, d);
+        }
+ 
+        H1 += a;
+        H2 += b;
+        H3 += c;
+        H4 += d;
+        H5 += e;
+        H6 += f;
+        H7 += g;
+        H8 += h;
+
+        //
+        // reset the offset and clean out the word buffer.
+        //
+        wOff = 0;
+        for (int i = 0; i < 16; i++)
+        {
+            W[i] = 0;
+        }
+    }
+
+    /* SHA-384 and SHA-512 functions (as for SHA-256 but for longs) */
+    private long Ch(
+        long    x,
+        long    y,
+        long    z)
+    {
+        return ((x & y) ^ ((~x) & z));
+    }
+
+    private long Maj(
+        long    x,
+        long    y,
+        long    z)
+    {
+        return ((x & y) ^ (x & z) ^ (y & z));
+    }
+
+    private long Sum0(
+        long    x)
+    {
+        return ((x << 36)|(x >>> 28)) ^ ((x << 30)|(x >>> 34)) ^ ((x << 25)|(x >>> 39));
+    }
+
+    private long Sum1(
+        long    x)
+    {
+        return ((x << 50)|(x >>> 14)) ^ ((x << 46)|(x >>> 18)) ^ ((x << 23)|(x >>> 41));
+    }
+
+    private long Sigma0(
+        long    x)
+    {
+        return ((x << 63)|(x >>> 1)) ^ ((x << 56)|(x >>> 8)) ^ (x >>> 7);
+    }
+
+    private long Sigma1(
+        long    x)
+    {
+        return ((x << 45)|(x >>> 19)) ^ ((x << 3)|(x >>> 61)) ^ (x >>> 6);
+    }
+
+    /* SHA-384 and SHA-512 Constants
+     * (represent the first 64 bits of the fractional parts of the
+     * cube roots of the first sixty-four prime numbers)
+     */
+    static final long K[] = {
+0x428a2f98d728ae22L, 0x7137449123ef65cdL, 0xb5c0fbcfec4d3b2fL, 0xe9b5dba58189dbbcL,
+0x3956c25bf348b538L, 0x59f111f1b605d019L, 0x923f82a4af194f9bL, 0xab1c5ed5da6d8118L,
+0xd807aa98a3030242L, 0x12835b0145706fbeL, 0x243185be4ee4b28cL, 0x550c7dc3d5ffb4e2L,
+0x72be5d74f27b896fL, 0x80deb1fe3b1696b1L, 0x9bdc06a725c71235L, 0xc19bf174cf692694L,
+0xe49b69c19ef14ad2L, 0xefbe4786384f25e3L, 0x0fc19dc68b8cd5b5L, 0x240ca1cc77ac9c65L,
+0x2de92c6f592b0275L, 0x4a7484aa6ea6e483L, 0x5cb0a9dcbd41fbd4L, 0x76f988da831153b5L,
+0x983e5152ee66dfabL, 0xa831c66d2db43210L, 0xb00327c898fb213fL, 0xbf597fc7beef0ee4L,
+0xc6e00bf33da88fc2L, 0xd5a79147930aa725L, 0x06ca6351e003826fL, 0x142929670a0e6e70L,
+0x27b70a8546d22ffcL, 0x2e1b21385c26c926L, 0x4d2c6dfc5ac42aedL, 0x53380d139d95b3dfL,
+0x650a73548baf63deL, 0x766a0abb3c77b2a8L, 0x81c2c92e47edaee6L, 0x92722c851482353bL,
+0xa2bfe8a14cf10364L, 0xa81a664bbc423001L, 0xc24b8b70d0f89791L, 0xc76c51a30654be30L,
+0xd192e819d6ef5218L, 0xd69906245565a910L, 0xf40e35855771202aL, 0x106aa07032bbd1b8L,
+0x19a4c116b8d2d0c8L, 0x1e376c085141ab53L, 0x2748774cdf8eeb99L, 0x34b0bcb5e19b48a8L,
+0x391c0cb3c5c95a63L, 0x4ed8aa4ae3418acbL, 0x5b9cca4f7763e373L, 0x682e6ff3d6b2b8a3L,
+0x748f82ee5defb2fcL, 0x78a5636f43172f60L, 0x84c87814a1f0ab72L, 0x8cc702081a6439ecL,
+0x90befffa23631e28L, 0xa4506cebde82bde9L, 0xbef9a3f7b2c67915L, 0xc67178f2e372532bL,
+0xca273eceea26619cL, 0xd186b8c721c0c207L, 0xeada7dd6cde0eb1eL, 0xf57d4f7fee6ed178L,
+0x06f067aa72176fbaL, 0x0a637dc5a2c898a6L, 0x113f9804bef90daeL, 0x1b710b35131c471bL,
+0x28db77f523047d84L, 0x32caab7b40c72493L, 0x3c9ebe0a15c9bebcL, 0x431d67c49c100d4cL,
+0x4cc5d4becb3e42b6L, 0x597f299cfc657e2aL, 0x5fcb6fab3ad6faecL, 0x6c44198c4a475817L
+    };
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/digests/MD2Digest.java b/libcore/security/src/main/java/org/bouncycastle/crypto/digests/MD2Digest.java
new file mode 100644
index 0000000..0edafbc
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/digests/MD2Digest.java
@@ -0,0 +1,237 @@
+package org.bouncycastle.crypto.digests;
+
+import org.bouncycastle.crypto.*;
+/**
+ * implementation of MD2
+ * as outlined in RFC1319 by B.Kaliski from RSA Laboratories April 1992
+ */
+public class MD2Digest
+    implements ExtendedDigest
+{
+    private static final int DIGEST_LENGTH = 16;
+
+    /* X buffer */
+    private byte[]   X = new byte[48];
+    private int     xOff;
+    /* M buffer */
+    private byte[]   M = new byte[16];
+    private int     mOff;
+    /* check sum */
+    private byte[]   C = new byte[16];
+    private int COff;
+
+    public MD2Digest()
+    {
+        reset();
+    }
+    public MD2Digest(MD2Digest t)
+    {
+        System.arraycopy(t.X, 0, X, 0, t.X.length);
+        xOff = t.xOff;
+        System.arraycopy(t.M, 0, M, 0, t.M.length);
+        mOff = t.mOff;
+        System.arraycopy(t.C, 0, C, 0, t.C.length);
+        COff = t.COff;
+    }
+    /**
+     * return the algorithm name
+     *
+     * @return the algorithm name
+     */
+    public String getAlgorithmName()
+    {
+        return "MD2";
+    }
+    /**
+     * return the size, in bytes, of the digest produced by this message digest.
+     *
+     * @return the size, in bytes, of the digest produced by this message digest.
+     */
+    public int getDigestSize()
+    {
+        return DIGEST_LENGTH;
+    }
+    /**
+     * close the digest, producing the final digest value. The doFinal
+     * call leaves the digest reset.
+     *
+     * @param out the array the digest is to be copied into.
+     * @param outOff the offset into the out array the digest is to start at.
+     */
+    public int doFinal(byte[] out, int outOff)
+    {
+        // add padding
+        byte paddingByte = (byte)(M.length-mOff);
+        for (int i=mOff;i<M.length;i++)
+        {
+            M[i] = paddingByte;
+        }
+        //do final check sum
+        processCheckSum(M);
+        // do final block process
+        processBlock(M);
+
+        processBlock(C);
+
+        System.arraycopy(X,xOff,out,outOff,16);
+
+        reset();
+
+        return DIGEST_LENGTH;
+    }
+    /**
+     * reset the digest back to it's initial state.
+     */
+    public void reset()
+    {
+        xOff = 0;
+        for (int i = 0; i != X.length; i++)
+        {
+            X[i] = 0;
+        }
+        mOff = 0;
+        for (int i = 0; i != M.length; i++)
+        {
+            M[i] = 0;
+        }
+        COff = 0;
+        for (int i = 0; i != C.length; i++)
+        {
+            C[i] = 0;
+        }
+    }
+    /**
+     * update the message digest with a single byte.
+     *
+     * @param in the input byte to be entered.
+     */
+    public void update(byte in)
+    {
+        M[mOff++] = in;
+
+        if (mOff == 16)
+        {
+            processCheckSum(M);
+            processBlock(M);
+            mOff = 0;
+        }
+    }
+
+    /**
+     * update the message digest with a block of bytes.
+     *
+     * @param in the byte array containing the data.
+     * @param inOff the offset into the byte array where the data starts.
+     * @param len the length of the data.
+     */
+    public void update(byte[] in, int inOff, int len)
+    {
+        //
+        // fill the current word
+        //
+        while ((mOff != 0) && (len > 0))
+        {
+            update(in[inOff]);
+            inOff++;
+            len--;
+        }
+
+        //
+        // process whole words.
+        //
+        while (len > 16)
+        {
+            System.arraycopy(in,inOff,M,0,16);
+            processCheckSum(M);
+            processBlock(M);
+            len -= 16;
+            inOff += 16;
+        }
+
+        //
+        // load in the remainder.
+        //
+        while (len > 0)
+        {
+            update(in[inOff]);
+            inOff++;
+            len--;
+        }
+    }
+    protected void processCheckSum(byte[] m)
+    {
+        int L = C[15];
+        for (int i=0;i<16;i++)
+        {
+            C[i] ^= S[(m[i] ^ L) & 0xff];
+            L = C[i];
+        }
+    }
+    protected void processBlock(byte[] m)
+    {
+        for (int i=0;i<16;i++)
+        {
+            X[i+16] = m[i];
+            X[i+32] = (byte)(m[i] ^ X[i]);
+        }
+        // encrypt block
+        int t = 0;
+
+        for (int j=0;j<18;j++)
+        {
+            for (int k=0;k<48;k++)
+            {
+                t = X[k] ^= S[t];
+                t = t & 0xff;
+            }
+            t = (t + j)%256;
+        }
+     }
+     // 256-byte random permutation constructed from the digits of PI
+    private static final byte[] S = {
+      (byte)41,(byte)46,(byte)67,(byte)201,(byte)162,(byte)216,(byte)124,
+      (byte)1,(byte)61,(byte)54,(byte)84,(byte)161,(byte)236,(byte)240,
+      (byte)6,(byte)19,(byte)98,(byte)167,(byte)5,(byte)243,(byte)192,
+      (byte)199,(byte)115,(byte)140,(byte)152,(byte)147,(byte)43,(byte)217,
+      (byte)188,(byte)76,(byte)130,(byte)202,(byte)30,(byte)155,(byte)87,
+      (byte)60,(byte)253,(byte)212,(byte)224,(byte)22,(byte)103,(byte)66,
+      (byte)111,(byte)24,(byte)138,(byte)23,(byte)229,(byte)18,(byte)190,
+      (byte)78,(byte)196,(byte)214,(byte)218,(byte)158,(byte)222,(byte)73,
+      (byte)160,(byte)251,(byte)245,(byte)142,(byte)187,(byte)47,(byte)238,
+      (byte)122,(byte)169,(byte)104,(byte)121,(byte)145,(byte)21,(byte)178,
+      (byte)7,(byte)63,(byte)148,(byte)194,(byte)16,(byte)137,(byte)11,
+      (byte)34,(byte)95,(byte)33,(byte)128,(byte)127,(byte)93,(byte)154,
+      (byte)90,(byte)144,(byte)50,(byte)39,(byte)53,(byte)62,(byte)204,
+      (byte)231,(byte)191,(byte)247,(byte)151,(byte)3,(byte)255,(byte)25,
+      (byte)48,(byte)179,(byte)72,(byte)165,(byte)181,(byte)209,(byte)215,
+      (byte)94,(byte)146,(byte)42,(byte)172,(byte)86,(byte)170,(byte)198,
+      (byte)79,(byte)184,(byte)56,(byte)210,(byte)150,(byte)164,(byte)125,
+      (byte)182,(byte)118,(byte)252,(byte)107,(byte)226,(byte)156,(byte)116,
+      (byte)4,(byte)241,(byte)69,(byte)157,(byte)112,(byte)89,(byte)100,
+      (byte)113,(byte)135,(byte)32,(byte)134,(byte)91,(byte)207,(byte)101,
+      (byte)230,(byte)45,(byte)168,(byte)2,(byte)27,(byte)96,(byte)37,
+      (byte)173,(byte)174,(byte)176,(byte)185,(byte)246,(byte)28,(byte)70,
+      (byte)97,(byte)105,(byte)52,(byte)64,(byte)126,(byte)15,(byte)85,
+      (byte)71,(byte)163,(byte)35,(byte)221,(byte)81,(byte)175,(byte)58,
+      (byte)195,(byte)92,(byte)249,(byte)206,(byte)186,(byte)197,(byte)234,
+      (byte)38,(byte)44,(byte)83,(byte)13,(byte)110,(byte)133,(byte)40,
+      (byte)132, 9,(byte)211,(byte)223,(byte)205,(byte)244,(byte)65,
+      (byte)129,(byte)77,(byte)82,(byte)106,(byte)220,(byte)55,(byte)200,
+      (byte)108,(byte)193,(byte)171,(byte)250,(byte)36,(byte)225,(byte)123,
+      (byte)8,(byte)12,(byte)189,(byte)177,(byte)74,(byte)120,(byte)136,
+      (byte)149,(byte)139,(byte)227,(byte)99,(byte)232,(byte)109,(byte)233,
+      (byte)203,(byte)213,(byte)254,(byte)59,(byte)0,(byte)29,(byte)57,
+      (byte)242,(byte)239,(byte)183,(byte)14,(byte)102,(byte)88,(byte)208,
+      (byte)228,(byte)166,(byte)119,(byte)114,(byte)248,(byte)235,(byte)117,
+      (byte)75,(byte)10,(byte)49,(byte)68,(byte)80,(byte)180,(byte)143,
+      (byte)237,(byte)31,(byte)26,(byte)219,(byte)153,(byte)141,(byte)51,
+      (byte)159,(byte)17,(byte)131,(byte)20
+    };
+
+   public int getByteLength() 
+   {
+      return 16;
+   }
+}
+
+
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/digests/MD4Digest.java b/libcore/security/src/main/java/org/bouncycastle/crypto/digests/MD4Digest.java
new file mode 100644
index 0000000..2a8084f
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/digests/MD4Digest.java
@@ -0,0 +1,270 @@
+package org.bouncycastle.crypto.digests;
+
+
+/**
+ * implementation of MD4 as RFC 1320 by R. Rivest, MIT Laboratory for
+ * Computer Science and RSA Data Security, Inc.
+ * <p>
+ * <b>NOTE</b>: This algorithm is only included for backwards compatability
+ * with legacy applications, it's not secure, don't use it for anything new!
+ */
+public class MD4Digest
+    extends GeneralDigest
+{
+    private static final int    DIGEST_LENGTH = 16;
+
+    private int     H1, H2, H3, H4;         // IV's
+
+    private int[]   X = new int[16];
+    private int     xOff;
+
+    /**
+     * Standard constructor
+     */
+    public MD4Digest()
+    {
+        reset();
+    }
+
+    /**
+     * Copy constructor.  This will copy the state of the provided
+     * message digest.
+     */
+    public MD4Digest(MD4Digest t)
+    {
+        super(t);
+
+        H1 = t.H1;
+        H2 = t.H2;
+        H3 = t.H3;
+        H4 = t.H4;
+
+        System.arraycopy(t.X, 0, X, 0, t.X.length);
+        xOff = t.xOff;
+    }
+
+    public String getAlgorithmName()
+    {
+        return "MD4";
+    }
+
+    public int getDigestSize()
+    {
+        return DIGEST_LENGTH;
+    }
+
+    protected void processWord(
+        byte[]  in,
+        int     inOff)
+    {
+        X[xOff++] = (in[inOff] & 0xff) | ((in[inOff + 1] & 0xff) << 8)
+            | ((in[inOff + 2] & 0xff) << 16) | ((in[inOff + 3] & 0xff) << 24); 
+
+        if (xOff == 16)
+        {
+            processBlock();
+        }
+    }
+
+    protected void processLength(
+        long    bitLength)
+    {
+        if (xOff > 14)
+        {
+            processBlock();
+        }
+
+        X[14] = (int)(bitLength & 0xffffffff);
+        X[15] = (int)(bitLength >>> 32);
+    }
+
+    private void unpackWord(
+        int     word,
+        byte[]  out,
+        int     outOff)
+    {
+        out[outOff]     = (byte)word;
+        out[outOff + 1] = (byte)(word >>> 8);
+        out[outOff + 2] = (byte)(word >>> 16);
+        out[outOff + 3] = (byte)(word >>> 24);
+    }
+
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+    {
+        finish();
+
+        unpackWord(H1, out, outOff);
+        unpackWord(H2, out, outOff + 4);
+        unpackWord(H3, out, outOff + 8);
+        unpackWord(H4, out, outOff + 12);
+
+        reset();
+
+        return DIGEST_LENGTH;
+    }
+
+    /**
+     * reset the chaining variables to the IV values.
+     */
+    public void reset()
+    {
+        super.reset();
+
+        H1 = 0x67452301;
+        H2 = 0xefcdab89;
+        H3 = 0x98badcfe;
+        H4 = 0x10325476;
+
+        xOff = 0;
+
+        for (int i = 0; i != X.length; i++)
+        {
+            X[i] = 0;
+        }
+    }
+
+    //
+    // round 1 left rotates
+    //
+    private static final int S11 = 3;
+    private static final int S12 = 7;
+    private static final int S13 = 11;
+    private static final int S14 = 19;
+
+    //
+    // round 2 left rotates
+    //
+    private static final int S21 = 3;
+    private static final int S22 = 5;
+    private static final int S23 = 9;
+    private static final int S24 = 13;
+
+    //
+    // round 3 left rotates
+    //
+    private static final int S31 = 3;
+    private static final int S32 = 9;
+    private static final int S33 = 11;
+    private static final int S34 = 15;
+
+    /*
+     * rotate int x left n bits.
+     */
+    private int rotateLeft(
+        int x,
+        int n)
+    {
+        return (x << n) | (x >>> (32 - n));
+    }
+
+    /*
+     * F, G, H and I are the basic MD4 functions.
+     */
+    private int F(
+        int u,
+        int v,
+        int w)
+    {
+        return (u & v) | (~u & w);
+    }
+
+    private int G(
+        int u,
+        int v,
+        int w)
+    {
+        return (u & v) | (u & w) | (v & w);
+    }
+
+    private int H(
+        int u,
+        int v,
+        int w)
+    {
+        return u ^ v ^ w;
+    }
+
+    protected void processBlock()
+    {
+        int a = H1;
+        int b = H2;
+        int c = H3;
+        int d = H4;
+
+        //
+        // Round 1 - F cycle, 16 times.
+        //
+        a = rotateLeft(a + F(b, c, d) + X[ 0], S11);
+        d = rotateLeft(d + F(a, b, c) + X[ 1], S12);
+        c = rotateLeft(c + F(d, a, b) + X[ 2], S13);
+        b = rotateLeft(b + F(c, d, a) + X[ 3], S14);
+        a = rotateLeft(a + F(b, c, d) + X[ 4], S11);
+        d = rotateLeft(d + F(a, b, c) + X[ 5], S12);
+        c = rotateLeft(c + F(d, a, b) + X[ 6], S13);
+        b = rotateLeft(b + F(c, d, a) + X[ 7], S14);
+        a = rotateLeft(a + F(b, c, d) + X[ 8], S11);
+        d = rotateLeft(d + F(a, b, c) + X[ 9], S12);
+        c = rotateLeft(c + F(d, a, b) + X[10], S13);
+        b = rotateLeft(b + F(c, d, a) + X[11], S14);
+        a = rotateLeft(a + F(b, c, d) + X[12], S11);
+        d = rotateLeft(d + F(a, b, c) + X[13], S12);
+        c = rotateLeft(c + F(d, a, b) + X[14], S13);
+        b = rotateLeft(b + F(c, d, a) + X[15], S14);
+
+        //
+        // Round 2 - G cycle, 16 times.
+        //
+        a = rotateLeft(a + G(b, c, d) + X[ 0] + 0x5a827999, S21);
+        d = rotateLeft(d + G(a, b, c) + X[ 4] + 0x5a827999, S22);
+        c = rotateLeft(c + G(d, a, b) + X[ 8] + 0x5a827999, S23);
+        b = rotateLeft(b + G(c, d, a) + X[12] + 0x5a827999, S24);
+        a = rotateLeft(a + G(b, c, d) + X[ 1] + 0x5a827999, S21);
+        d = rotateLeft(d + G(a, b, c) + X[ 5] + 0x5a827999, S22);
+        c = rotateLeft(c + G(d, a, b) + X[ 9] + 0x5a827999, S23);
+        b = rotateLeft(b + G(c, d, a) + X[13] + 0x5a827999, S24);
+        a = rotateLeft(a + G(b, c, d) + X[ 2] + 0x5a827999, S21);
+        d = rotateLeft(d + G(a, b, c) + X[ 6] + 0x5a827999, S22);
+        c = rotateLeft(c + G(d, a, b) + X[10] + 0x5a827999, S23);
+        b = rotateLeft(b + G(c, d, a) + X[14] + 0x5a827999, S24);
+        a = rotateLeft(a + G(b, c, d) + X[ 3] + 0x5a827999, S21);
+        d = rotateLeft(d + G(a, b, c) + X[ 7] + 0x5a827999, S22);
+        c = rotateLeft(c + G(d, a, b) + X[11] + 0x5a827999, S23);
+        b = rotateLeft(b + G(c, d, a) + X[15] + 0x5a827999, S24);
+
+        //
+        // Round 3 - H cycle, 16 times.
+        //
+        a = rotateLeft(a + H(b, c, d) + X[ 0] + 0x6ed9eba1, S31);
+        d = rotateLeft(d + H(a, b, c) + X[ 8] + 0x6ed9eba1, S32);
+        c = rotateLeft(c + H(d, a, b) + X[ 4] + 0x6ed9eba1, S33);
+        b = rotateLeft(b + H(c, d, a) + X[12] + 0x6ed9eba1, S34);
+        a = rotateLeft(a + H(b, c, d) + X[ 2] + 0x6ed9eba1, S31);
+        d = rotateLeft(d + H(a, b, c) + X[10] + 0x6ed9eba1, S32);
+        c = rotateLeft(c + H(d, a, b) + X[ 6] + 0x6ed9eba1, S33);
+        b = rotateLeft(b + H(c, d, a) + X[14] + 0x6ed9eba1, S34);
+        a = rotateLeft(a + H(b, c, d) + X[ 1] + 0x6ed9eba1, S31);
+        d = rotateLeft(d + H(a, b, c) + X[ 9] + 0x6ed9eba1, S32);
+        c = rotateLeft(c + H(d, a, b) + X[ 5] + 0x6ed9eba1, S33);
+        b = rotateLeft(b + H(c, d, a) + X[13] + 0x6ed9eba1, S34);
+        a = rotateLeft(a + H(b, c, d) + X[ 3] + 0x6ed9eba1, S31);
+        d = rotateLeft(d + H(a, b, c) + X[11] + 0x6ed9eba1, S32);
+        c = rotateLeft(c + H(d, a, b) + X[ 7] + 0x6ed9eba1, S33);
+        b = rotateLeft(b + H(c, d, a) + X[15] + 0x6ed9eba1, S34);
+
+        H1 += a;
+        H2 += b;
+        H3 += c;
+        H4 += d;
+
+        //
+        // reset the offset and clean out the word buffer.
+        //
+        xOff = 0;
+        for (int i = 0; i != X.length; i++)
+        {
+            X[i] = 0;
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/digests/MD5Digest.java b/libcore/security/src/main/java/org/bouncycastle/crypto/digests/MD5Digest.java
new file mode 100644
index 0000000..05ed27a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/digests/MD5Digest.java
@@ -0,0 +1,302 @@
+package org.bouncycastle.crypto.digests;
+
+
+/**
+ * implementation of MD5 as outlined in "Handbook of Applied Cryptography", pages 346 - 347.
+ */
+public class MD5Digest
+    extends GeneralDigest
+{
+    private static final int    DIGEST_LENGTH = 16;
+
+    private int     H1, H2, H3, H4;         // IV's
+
+    private int[]   X = new int[16];
+    private int     xOff;
+
+    /**
+     * Standard constructor
+     */
+    public MD5Digest()
+    {
+        reset();
+    }
+
+    /**
+     * Copy constructor.  This will copy the state of the provided
+     * message digest.
+     */
+    public MD5Digest(MD5Digest t)
+    {
+        super(t);
+
+        H1 = t.H1;
+        H2 = t.H2;
+        H3 = t.H3;
+        H4 = t.H4;
+
+        System.arraycopy(t.X, 0, X, 0, t.X.length);
+        xOff = t.xOff;
+    }
+
+    public String getAlgorithmName()
+    {
+        return "MD5";
+    }
+
+    public int getDigestSize()
+    {
+        return DIGEST_LENGTH;
+    }
+
+    protected void processWord(
+        byte[]  in,
+        int     inOff)
+    {
+        X[xOff++] = (in[inOff] & 0xff) | ((in[inOff + 1] & 0xff) << 8)
+            | ((in[inOff + 2] & 0xff) << 16) | ((in[inOff + 3] & 0xff) << 24); 
+
+        if (xOff == 16)
+        {
+            processBlock();
+        }
+    }
+
+    protected void processLength(
+        long    bitLength)
+    {
+        if (xOff > 14)
+        {
+            processBlock();
+        }
+
+        X[14] = (int)(bitLength & 0xffffffff);
+        X[15] = (int)(bitLength >>> 32);
+    }
+
+    private void unpackWord(
+        int     word,
+        byte[]  out,
+        int     outOff)
+    {
+        out[outOff]     = (byte)word;
+        out[outOff + 1] = (byte)(word >>> 8);
+        out[outOff + 2] = (byte)(word >>> 16);
+        out[outOff + 3] = (byte)(word >>> 24);
+    }
+
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+    {
+        finish();
+
+        unpackWord(H1, out, outOff);
+        unpackWord(H2, out, outOff + 4);
+        unpackWord(H3, out, outOff + 8);
+        unpackWord(H4, out, outOff + 12);
+
+        reset();
+
+        return DIGEST_LENGTH;
+    }
+
+    /**
+     * reset the chaining variables to the IV values.
+     */
+    public void reset()
+    {
+        super.reset();
+
+        H1 = 0x67452301;
+        H2 = 0xefcdab89;
+        H3 = 0x98badcfe;
+        H4 = 0x10325476;
+
+        xOff = 0;
+
+        for (int i = 0; i != X.length; i++)
+        {
+            X[i] = 0;
+        }
+    }
+
+    //
+    // round 1 left rotates
+    //
+    private static final int S11 = 7;
+    private static final int S12 = 12;
+    private static final int S13 = 17;
+    private static final int S14 = 22;
+
+    //
+    // round 2 left rotates
+    //
+    private static final int S21 = 5;
+    private static final int S22 = 9;
+    private static final int S23 = 14;
+    private static final int S24 = 20;
+
+    //
+    // round 3 left rotates
+    //
+    private static final int S31 = 4;
+    private static final int S32 = 11;
+    private static final int S33 = 16;
+    private static final int S34 = 23;
+
+    //
+    // round 4 left rotates
+    //
+    private static final int S41 = 6;
+    private static final int S42 = 10;
+    private static final int S43 = 15;
+    private static final int S44 = 21;
+
+    /*
+     * rotate int x left n bits.
+     */
+    private int rotateLeft(
+        int x,
+        int n)
+    {
+        return (x << n) | (x >>> (32 - n));
+    }
+
+    /*
+     * F, G, H and I are the basic MD5 functions.
+     */
+    private int F(
+        int u,
+        int v,
+        int w)
+    {
+        return (u & v) | (~u & w);
+    }
+
+    private int G(
+        int u,
+        int v,
+        int w)
+    {
+        return (u & w) | (v & ~w);
+    }
+
+    private int H(
+        int u,
+        int v,
+        int w)
+    {
+        return u ^ v ^ w;
+    }
+
+    private int K(
+        int u,
+        int v,
+        int w)
+    {
+        return v ^ (u | ~w);
+    }
+
+    protected void processBlock()
+    {
+        int a = H1;
+        int b = H2;
+        int c = H3;
+        int d = H4;
+
+        //
+        // Round 1 - F cycle, 16 times.
+        //
+        a = rotateLeft(a + F(b, c, d) + X[ 0] + 0xd76aa478, S11) + b;
+        d = rotateLeft(d + F(a, b, c) + X[ 1] + 0xe8c7b756, S12) + a;
+        c = rotateLeft(c + F(d, a, b) + X[ 2] + 0x242070db, S13) + d;
+        b = rotateLeft(b + F(c, d, a) + X[ 3] + 0xc1bdceee, S14) + c;
+        a = rotateLeft(a + F(b, c, d) + X[ 4] + 0xf57c0faf, S11) + b;
+        d = rotateLeft(d + F(a, b, c) + X[ 5] + 0x4787c62a, S12) + a;
+        c = rotateLeft(c + F(d, a, b) + X[ 6] + 0xa8304613, S13) + d;
+        b = rotateLeft(b + F(c, d, a) + X[ 7] + 0xfd469501, S14) + c;
+        a = rotateLeft(a + F(b, c, d) + X[ 8] + 0x698098d8, S11) + b;
+        d = rotateLeft(d + F(a, b, c) + X[ 9] + 0x8b44f7af, S12) + a;
+        c = rotateLeft(c + F(d, a, b) + X[10] + 0xffff5bb1, S13) + d;
+        b = rotateLeft(b + F(c, d, a) + X[11] + 0x895cd7be, S14) + c;
+        a = rotateLeft(a + F(b, c, d) + X[12] + 0x6b901122, S11) + b;
+        d = rotateLeft(d + F(a, b, c) + X[13] + 0xfd987193, S12) + a;
+        c = rotateLeft(c + F(d, a, b) + X[14] + 0xa679438e, S13) + d;
+        b = rotateLeft(b + F(c, d, a) + X[15] + 0x49b40821, S14) + c;
+
+        //
+        // Round 2 - G cycle, 16 times.
+        //
+        a = rotateLeft(a + G(b, c, d) + X[ 1] + 0xf61e2562, S21) + b;
+        d = rotateLeft(d + G(a, b, c) + X[ 6] + 0xc040b340, S22) + a;
+        c = rotateLeft(c + G(d, a, b) + X[11] + 0x265e5a51, S23) + d;
+        b = rotateLeft(b + G(c, d, a) + X[ 0] + 0xe9b6c7aa, S24) + c;
+        a = rotateLeft(a + G(b, c, d) + X[ 5] + 0xd62f105d, S21) + b;
+        d = rotateLeft(d + G(a, b, c) + X[10] + 0x02441453, S22) + a;
+        c = rotateLeft(c + G(d, a, b) + X[15] + 0xd8a1e681, S23) + d;
+        b = rotateLeft(b + G(c, d, a) + X[ 4] + 0xe7d3fbc8, S24) + c;
+        a = rotateLeft(a + G(b, c, d) + X[ 9] + 0x21e1cde6, S21) + b;
+        d = rotateLeft(d + G(a, b, c) + X[14] + 0xc33707d6, S22) + a;
+        c = rotateLeft(c + G(d, a, b) + X[ 3] + 0xf4d50d87, S23) + d;
+        b = rotateLeft(b + G(c, d, a) + X[ 8] + 0x455a14ed, S24) + c;
+        a = rotateLeft(a + G(b, c, d) + X[13] + 0xa9e3e905, S21) + b;
+        d = rotateLeft(d + G(a, b, c) + X[ 2] + 0xfcefa3f8, S22) + a;
+        c = rotateLeft(c + G(d, a, b) + X[ 7] + 0x676f02d9, S23) + d;
+        b = rotateLeft(b + G(c, d, a) + X[12] + 0x8d2a4c8a, S24) + c;
+
+        //
+        // Round 3 - H cycle, 16 times.
+        //
+        a = rotateLeft(a + H(b, c, d) + X[ 5] + 0xfffa3942, S31) + b;
+        d = rotateLeft(d + H(a, b, c) + X[ 8] + 0x8771f681, S32) + a;
+        c = rotateLeft(c + H(d, a, b) + X[11] + 0x6d9d6122, S33) + d;
+        b = rotateLeft(b + H(c, d, a) + X[14] + 0xfde5380c, S34) + c;
+        a = rotateLeft(a + H(b, c, d) + X[ 1] + 0xa4beea44, S31) + b;
+        d = rotateLeft(d + H(a, b, c) + X[ 4] + 0x4bdecfa9, S32) + a;
+        c = rotateLeft(c + H(d, a, b) + X[ 7] + 0xf6bb4b60, S33) + d;
+        b = rotateLeft(b + H(c, d, a) + X[10] + 0xbebfbc70, S34) + c;
+        a = rotateLeft(a + H(b, c, d) + X[13] + 0x289b7ec6, S31) + b;
+        d = rotateLeft(d + H(a, b, c) + X[ 0] + 0xeaa127fa, S32) + a;
+        c = rotateLeft(c + H(d, a, b) + X[ 3] + 0xd4ef3085, S33) + d;
+        b = rotateLeft(b + H(c, d, a) + X[ 6] + 0x04881d05, S34) + c;
+        a = rotateLeft(a + H(b, c, d) + X[ 9] + 0xd9d4d039, S31) + b;
+        d = rotateLeft(d + H(a, b, c) + X[12] + 0xe6db99e5, S32) + a;
+        c = rotateLeft(c + H(d, a, b) + X[15] + 0x1fa27cf8, S33) + d;
+        b = rotateLeft(b + H(c, d, a) + X[ 2] + 0xc4ac5665, S34) + c;
+
+        //
+        // Round 4 - K cycle, 16 times.
+        //
+        a = rotateLeft(a + K(b, c, d) + X[ 0] + 0xf4292244, S41) + b;
+        d = rotateLeft(d + K(a, b, c) + X[ 7] + 0x432aff97, S42) + a;
+        c = rotateLeft(c + K(d, a, b) + X[14] + 0xab9423a7, S43) + d;
+        b = rotateLeft(b + K(c, d, a) + X[ 5] + 0xfc93a039, S44) + c;
+        a = rotateLeft(a + K(b, c, d) + X[12] + 0x655b59c3, S41) + b;
+        d = rotateLeft(d + K(a, b, c) + X[ 3] + 0x8f0ccc92, S42) + a;
+        c = rotateLeft(c + K(d, a, b) + X[10] + 0xffeff47d, S43) + d;
+        b = rotateLeft(b + K(c, d, a) + X[ 1] + 0x85845dd1, S44) + c;
+        a = rotateLeft(a + K(b, c, d) + X[ 8] + 0x6fa87e4f, S41) + b;
+        d = rotateLeft(d + K(a, b, c) + X[15] + 0xfe2ce6e0, S42) + a;
+        c = rotateLeft(c + K(d, a, b) + X[ 6] + 0xa3014314, S43) + d;
+        b = rotateLeft(b + K(c, d, a) + X[13] + 0x4e0811a1, S44) + c;
+        a = rotateLeft(a + K(b, c, d) + X[ 4] + 0xf7537e82, S41) + b;
+        d = rotateLeft(d + K(a, b, c) + X[11] + 0xbd3af235, S42) + a;
+        c = rotateLeft(c + K(d, a, b) + X[ 2] + 0x2ad7d2bb, S43) + d;
+        b = rotateLeft(b + K(c, d, a) + X[ 9] + 0xeb86d391, S44) + c;
+
+        H1 += a;
+        H2 += b;
+        H3 += c;
+        H4 += d;
+
+        //
+        // reset the offset and clean out the word buffer.
+        //
+        xOff = 0;
+        for (int i = 0; i != X.length; i++)
+        {
+            X[i] = 0;
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java b/libcore/security/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java
new file mode 100644
index 0000000..9b282e9
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java
@@ -0,0 +1,294 @@
+package org.bouncycastle.crypto.digests;
+
+/**
+ * implementation of SHA-1 as outlined in "Handbook of Applied Cryptography", pages 346 - 349.
+ *
+ * It is interesting to ponder why the, apart from the extra IV, the other difference here from MD5
+ * is the "endienness" of the word processing!
+ */
+public class SHA1Digest
+    extends GeneralDigest
+{
+    private static final int    DIGEST_LENGTH = 20;
+
+    private int     H1, H2, H3, H4, H5;
+
+    private int[]   X = new int[80];
+    private int     xOff;
+
+    /**
+     * Standard constructor
+     */
+    public SHA1Digest()
+    {
+        reset();
+    }
+
+    /**
+     * Copy constructor.  This will copy the state of the provided
+     * message digest.
+     */
+    public SHA1Digest(SHA1Digest t)
+    {
+        super(t);
+
+        H1 = t.H1;
+        H2 = t.H2;
+        H3 = t.H3;
+        H4 = t.H4;
+        H5 = t.H5;
+
+        System.arraycopy(t.X, 0, X, 0, t.X.length);
+        xOff = t.xOff;
+    }
+
+    public String getAlgorithmName()
+    {
+        return "SHA-1";
+    }
+
+    public int getDigestSize()
+    {
+        return DIGEST_LENGTH;
+    }
+
+    protected void processWord(
+        byte[]  in,
+        int     inOff)
+    {
+        X[xOff++] = (in[inOff] & 0xff) << 24 | (in[inOff + 1] & 0xff) << 16
+                    | (in[inOff + 2] & 0xff) << 8 | in[inOff + 3] & 0xff; 
+
+        if (xOff == 16)
+        {
+            processBlock();
+        }        
+    }
+
+    private void unpackWord(
+        int     word,
+        byte[]  out,
+        int     outOff)
+    {
+        out[outOff++] = (byte)(word >>> 24);
+        out[outOff++] = (byte)(word >>> 16);
+        out[outOff++] = (byte)(word >>> 8);
+        out[outOff++] = (byte)word;
+    }
+
+    protected void processLength(
+        long    bitLength)
+    {
+        if (xOff > 14)
+        {
+            processBlock();
+        }
+
+        X[14] = (int)(bitLength >>> 32);
+        X[15] = (int)(bitLength & 0xffffffff);
+    }
+
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+    {
+        finish();
+
+        unpackWord(H1, out, outOff);
+        unpackWord(H2, out, outOff + 4);
+        unpackWord(H3, out, outOff + 8);
+        unpackWord(H4, out, outOff + 12);
+        unpackWord(H5, out, outOff + 16);
+
+        reset();
+
+        return DIGEST_LENGTH;
+    }
+
+    /**
+     * reset the chaining variables
+     */
+    public void reset()
+    {
+        super.reset();
+
+        H1 = 0x67452301;
+        H2 = 0xefcdab89;
+        H3 = 0x98badcfe;
+        H4 = 0x10325476;
+        H5 = 0xc3d2e1f0;
+
+        xOff = 0;
+        for (int i = 0; i != X.length; i++)
+        {
+            X[i] = 0;
+        }
+    }
+
+    //
+    // Additive constants
+    //
+    private static final int    Y1 = 0x5a827999;
+    private static final int    Y2 = 0x6ed9eba1;
+    private static final int    Y3 = 0x8f1bbcdc;
+    private static final int    Y4 = 0xca62c1d6;
+   
+    private int f(
+        int    u,
+        int    v,
+        int    w)
+    {
+        return ((u & v) | ((~u) & w));
+    }
+
+    private int h(
+        int    u,
+        int    v,
+        int    w)
+    {
+        return (u ^ v ^ w);
+    }
+
+    private int g(
+        int    u,
+        int    v,
+        int    w)
+    {
+        return ((u & v) | (u & w) | (v & w));
+    }
+
+    protected void processBlock()
+    {
+        //
+        // expand 16 word block into 80 word block.
+        //
+        for (int i = 16; i < 80; i++)
+        {
+            int t = X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16];
+            X[i] = t << 1 | t >>> 31;
+        }
+
+        //
+        // set up working variables.
+        //
+        int     A = H1;
+        int     B = H2;
+        int     C = H3;
+        int     D = H4;
+        int     E = H5;
+
+        //
+        // round 1
+        //
+        int idx = 0;
+        
+        for (int j = 0; j < 4; j++)
+        {
+            // E = rotateLeft(A, 5) + f(B, C, D) + E + X[idx++] + Y1
+            // B = rotateLeft(B, 30)
+            E += (A << 5 | A >>> 27) + f(B, C, D) + X[idx++] + Y1;
+            B = B << 30 | B >>> 2;
+        
+            D += (E << 5 | E >>> 27) + f(A, B, C) + X[idx++] + Y1;
+            A = A << 30 | A >>> 2;
+       
+            C += (D << 5 | D >>> 27) + f(E, A, B) + X[idx++] + Y1;
+            E = E << 30 | E >>> 2;
+       
+            B += (C << 5 | C >>> 27) + f(D, E, A) + X[idx++] + Y1;
+            D = D << 30 | D >>> 2;
+
+            A += (B << 5 | B >>> 27) + f(C, D, E) + X[idx++] + Y1;
+            C = C << 30 | C >>> 2;
+        }
+        
+        //
+        // round 2
+        //
+        for (int j = 0; j < 4; j++)
+        {
+            // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y2
+            // B = rotateLeft(B, 30)
+            E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y2;
+            B = B << 30 | B >>> 2;   
+            
+            D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y2;
+            A = A << 30 | A >>> 2;
+            
+            C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y2;
+            E = E << 30 | E >>> 2;
+            
+            B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y2;
+            D = D << 30 | D >>> 2;
+
+            A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y2;
+            C = C << 30 | C >>> 2;
+        }
+        
+        //
+        // round 3
+        //
+        for (int j = 0; j < 4; j++)
+        {
+            // E = rotateLeft(A, 5) + g(B, C, D) + E + X[idx++] + Y3
+            // B = rotateLeft(B, 30)
+            E += (A << 5 | A >>> 27) + g(B, C, D) + X[idx++] + Y3;
+            B = B << 30 | B >>> 2;
+            
+            D += (E << 5 | E >>> 27) + g(A, B, C) + X[idx++] + Y3;
+            A = A << 30 | A >>> 2;
+            
+            C += (D << 5 | D >>> 27) + g(E, A, B) + X[idx++] + Y3;
+            E = E << 30 | E >>> 2;
+            
+            B += (C << 5 | C >>> 27) + g(D, E, A) + X[idx++] + Y3;
+            D = D << 30 | D >>> 2;
+
+            A += (B << 5 | B >>> 27) + g(C, D, E) + X[idx++] + Y3;
+            C = C << 30 | C >>> 2;
+        }
+
+        //
+        // round 4
+        //
+        for (int j = 0; j <= 3; j++)
+        {
+            // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y4
+            // B = rotateLeft(B, 30)
+            E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y4;
+            B = B << 30 | B >>> 2;
+            
+            D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y4;
+            A = A << 30 | A >>> 2;
+            
+            C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y4;
+            E = E << 30 | E >>> 2;
+            
+            B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y4;
+            D = D << 30 | D >>> 2;
+
+            A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y4;
+            C = C << 30 | C >>> 2;
+        }
+
+
+        H1 += A;
+        H2 += B;
+        H3 += C;
+        H4 += D;
+        H5 += E;
+
+        //
+        // reset start of the buffer.
+        //
+        xOff = 0;
+        for (int i = 0; i < 16; i++)
+        {
+            X[i] = 0;
+        }
+    }
+}
+
+
+
+
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java b/libcore/security/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java
new file mode 100644
index 0000000..392d12b
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java
@@ -0,0 +1,289 @@
+package org.bouncycastle.crypto.digests;
+
+
+import org.bouncycastle.crypto.digests.GeneralDigest;
+
+
+/**
+ * SHA-224 as described in RFC 3874
+ * <pre>
+ *         block  word  digest
+ * SHA-1   512    32    160
+ * SHA-224 512    32    224
+ * SHA-256 512    32    256
+ * SHA-384 1024   64    384
+ * SHA-512 1024   64    512
+ * </pre>
+ */
+public class SHA224Digest
+    extends GeneralDigest
+{
+    private static final int    DIGEST_LENGTH = 28;
+
+    private int     H1, H2, H3, H4, H5, H6, H7, H8;
+
+    private int[]   X = new int[64];
+    private int     xOff;
+
+    /**
+     * Standard constructor
+     */
+    public SHA224Digest()
+    {
+        reset();
+    }
+
+    /**
+     * Copy constructor.  This will copy the state of the provided
+     * message digest.
+     */
+    public SHA224Digest(SHA224Digest t)
+    {
+        super(t);
+
+        H1 = t.H1;
+        H2 = t.H2;
+        H3 = t.H3;
+        H4 = t.H4;
+        H5 = t.H5;
+        H6 = t.H6;
+        H7 = t.H7;
+        H8 = t.H8;
+
+        System.arraycopy(t.X, 0, X, 0, t.X.length);
+        xOff = t.xOff;
+    }
+
+    public String getAlgorithmName()
+    {
+        return "SHA-224";
+    }
+
+    public int getDigestSize()
+    {
+        return DIGEST_LENGTH;
+    }
+
+    protected void processWord(
+        byte[]  in,
+        int     inOff)
+    {
+        X[xOff++] = ((in[inOff] & 0xff) << 24) | ((in[inOff + 1] & 0xff) << 16)
+                    | ((in[inOff + 2] & 0xff) << 8) | ((in[inOff + 3] & 0xff)); 
+
+        if (xOff == 16)
+        {
+            processBlock();
+        }
+    }
+
+    private void unpackWord(
+        int     word,
+        byte[]  out,
+        int     outOff)
+    {
+        out[outOff]     = (byte)(word >>> 24);
+        out[outOff + 1] = (byte)(word >>> 16);
+        out[outOff + 2] = (byte)(word >>> 8);
+        out[outOff + 3] = (byte)word;
+    }
+
+    protected void processLength(
+        long    bitLength)
+    {
+        if (xOff > 14)
+        {
+            processBlock();
+        }
+
+        X[14] = (int)(bitLength >>> 32);
+        X[15] = (int)(bitLength & 0xffffffff);
+    }
+
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+    {
+        finish();
+
+        unpackWord(H1, out, outOff);
+        unpackWord(H2, out, outOff + 4);
+        unpackWord(H3, out, outOff + 8);
+        unpackWord(H4, out, outOff + 12);
+        unpackWord(H5, out, outOff + 16);
+        unpackWord(H6, out, outOff + 20);
+        unpackWord(H7, out, outOff + 24);
+
+        reset();
+
+        return DIGEST_LENGTH;
+    }
+
+    /**
+     * reset the chaining variables
+     */
+    public void reset()
+    {
+        super.reset();
+
+        /* SHA-224 initial hash value
+         */
+
+        H1 = 0xc1059ed8;
+        H2 = 0x367cd507;
+        H3 = 0x3070dd17;
+        H4 = 0xf70e5939;
+        H5 = 0xffc00b31;
+        H6 = 0x68581511;
+        H7 = 0x64f98fa7;
+        H8 = 0xbefa4fa4;
+
+        xOff = 0;
+        for (int i = 0; i != X.length; i++)
+        {
+            X[i] = 0;
+        }
+    }
+
+    protected void processBlock()
+    {
+        //
+        // expand 16 word block into 64 word blocks.
+        //
+        for (int t = 16; t <= 63; t++)
+        {
+            X[t] = Theta1(X[t - 2]) + X[t - 7] + Theta0(X[t - 15]) + X[t - 16];
+        }
+
+        //
+        // set up working variables.
+        //
+        int     a = H1;
+        int     b = H2;
+        int     c = H3;
+        int     d = H4;
+        int     e = H5;
+        int     f = H6;
+        int     g = H7;
+        int     h = H8;
+
+
+        int t = 0;     
+        for(int i = 0; i < 8; i ++)
+        {
+            // t = 8 * i
+            h += Sum1(e) + Ch(e, f, g) + K[t] + X[t++];
+            d += h;
+            h += Sum0(a) + Maj(a, b, c);
+
+            // t = 8 * i + 1
+            g += Sum1(d) + Ch(d, e, f) + K[t] + X[t++];
+            c += g;
+            g += Sum0(h) + Maj(h, a, b);
+
+            // t = 8 * i + 2
+            f += Sum1(c) + Ch(c, d, e) + K[t] + X[t++];
+            b += f;
+            f += Sum0(g) + Maj(g, h, a);
+
+            // t = 8 * i + 3
+            e += Sum1(b) + Ch(b, c, d) + K[t] + X[t++];
+            a += e;
+            e += Sum0(f) + Maj(f, g, h);
+
+            // t = 8 * i + 4
+            d += Sum1(a) + Ch(a, b, c) + K[t] + X[t++];
+            h += d;
+            d += Sum0(e) + Maj(e, f, g);
+
+            // t = 8 * i + 5
+            c += Sum1(h) + Ch(h, a, b) + K[t] + X[t++];
+            g += c;
+            c += Sum0(d) + Maj(d, e, f);
+
+            // t = 8 * i + 6
+            b += Sum1(g) + Ch(g, h, a) + K[t] + X[t++];
+            f += b;
+            b += Sum0(c) + Maj(c, d, e);
+
+            // t = 8 * i + 7
+            a += Sum1(f) + Ch(f, g, h) + K[t] + X[t++];
+            e += a;
+            a += Sum0(b) + Maj(b, c, d);
+        }
+
+        H1 += a;
+        H2 += b;
+        H3 += c;
+        H4 += d;
+        H5 += e;
+        H6 += f;
+        H7 += g;
+        H8 += h;
+
+        //
+        // reset the offset and clean out the word buffer.
+        //
+        xOff = 0;
+        for (int i = 0; i < 16; i++)
+        {
+            X[i] = 0;
+        }
+    }
+
+    /* SHA-224 functions */
+    private int Ch(
+        int    x,
+        int    y,
+        int    z)
+    {
+        return ((x & y) ^ ((~x) & z));
+    }
+
+    private int Maj(
+        int    x,
+        int    y,
+        int    z)
+    {
+        return ((x & y) ^ (x & z) ^ (y & z));
+    }
+
+    private int Sum0(
+        int    x)
+    {
+        return ((x >>> 2) | (x << 30)) ^ ((x >>> 13) | (x << 19)) ^ ((x >>> 22) | (x << 10));
+    }
+
+    private int Sum1(
+        int    x)
+    {
+        return ((x >>> 6) | (x << 26)) ^ ((x >>> 11) | (x << 21)) ^ ((x >>> 25) | (x << 7));
+    }
+
+    private int Theta0(
+        int    x)
+    {
+        return ((x >>> 7) | (x << 25)) ^ ((x >>> 18) | (x << 14)) ^ (x >>> 3);
+    }
+
+    private int Theta1(
+        int    x)
+    {
+        return ((x >>> 17) | (x << 15)) ^ ((x >>> 19) | (x << 13)) ^ (x >>> 10);
+    }
+
+    /* SHA-224 Constants
+     * (represent the first 32 bits of the fractional parts of the
+     * cube roots of the first sixty-four prime numbers)
+     */
+    static final int K[] = {
+        0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+        0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+        0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+        0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+        0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+        0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+        0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java b/libcore/security/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java
new file mode 100644
index 0000000..d9cbc44
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java
@@ -0,0 +1,291 @@
+package org.bouncycastle.crypto.digests;
+
+
+import org.bouncycastle.crypto.digests.GeneralDigest;
+
+
+/**
+ * FIPS 180-2 implementation of SHA-256.
+ *
+ * <pre>
+ *         block  word  digest
+ * SHA-1   512    32    160
+ * SHA-256 512    32    256
+ * SHA-384 1024   64    384
+ * SHA-512 1024   64    512
+ * </pre>
+ */
+public class SHA256Digest
+    extends GeneralDigest
+{
+    private static final int    DIGEST_LENGTH = 32;
+
+    private int     H1, H2, H3, H4, H5, H6, H7, H8;
+
+    private int[]   X = new int[64];
+    private int     xOff;
+
+    /**
+     * Standard constructor
+     */
+    public SHA256Digest()
+    {
+        reset();
+    }
+
+    /**
+     * Copy constructor.  This will copy the state of the provided
+     * message digest.
+     */
+    public SHA256Digest(SHA256Digest t)
+    {
+        super(t);
+
+        H1 = t.H1;
+        H2 = t.H2;
+        H3 = t.H3;
+        H4 = t.H4;
+        H5 = t.H5;
+        H6 = t.H6;
+        H7 = t.H7;
+        H8 = t.H8;
+
+        System.arraycopy(t.X, 0, X, 0, t.X.length);
+        xOff = t.xOff;
+    }
+
+    public String getAlgorithmName()
+    {
+        return "SHA-256";
+    }
+
+    public int getDigestSize()
+    {
+        return DIGEST_LENGTH;
+    }
+
+    protected void processWord(
+        byte[]  in,
+        int     inOff)
+    {
+        X[xOff++] = ((in[inOff] & 0xff) << 24) | ((in[inOff + 1] & 0xff) << 16)
+                    | ((in[inOff + 2] & 0xff) << 8) | ((in[inOff + 3] & 0xff)); 
+
+        if (xOff == 16)
+        {
+            processBlock();
+        }
+    }
+
+    private void unpackWord(
+        int     word,
+        byte[]  out,
+        int     outOff)
+    {
+        out[outOff]     = (byte)(word >>> 24);
+        out[outOff + 1] = (byte)(word >>> 16);
+        out[outOff + 2] = (byte)(word >>> 8);
+        out[outOff + 3] = (byte)word;
+    }
+
+    protected void processLength(
+        long    bitLength)
+    {
+        if (xOff > 14)
+        {
+            processBlock();
+        }
+
+        X[14] = (int)(bitLength >>> 32);
+        X[15] = (int)(bitLength & 0xffffffff);
+    }
+
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+    {
+        finish();
+
+        unpackWord(H1, out, outOff);
+        unpackWord(H2, out, outOff + 4);
+        unpackWord(H3, out, outOff + 8);
+        unpackWord(H4, out, outOff + 12);
+        unpackWord(H5, out, outOff + 16);
+        unpackWord(H6, out, outOff + 20);
+        unpackWord(H7, out, outOff + 24);
+        unpackWord(H8, out, outOff + 28);
+
+        reset();
+
+        return DIGEST_LENGTH;
+    }
+
+    /**
+     * reset the chaining variables
+     */
+    public void reset()
+    {
+        super.reset();
+
+        /* SHA-256 initial hash value
+         * The first 32 bits of the fractional parts of the square roots
+         * of the first eight prime numbers
+         */
+
+        H1 = 0x6a09e667;
+        H2 = 0xbb67ae85;
+        H3 = 0x3c6ef372;
+        H4 = 0xa54ff53a;
+        H5 = 0x510e527f;
+        H6 = 0x9b05688c;
+        H7 = 0x1f83d9ab;
+        H8 = 0x5be0cd19;
+
+        xOff = 0;
+        for (int i = 0; i != X.length; i++)
+        {
+            X[i] = 0;
+        }
+    }
+
+    protected void processBlock()
+    {
+        //
+        // expand 16 word block into 64 word blocks.
+        //
+        for (int t = 16; t <= 63; t++)
+        {
+            X[t] = Theta1(X[t - 2]) + X[t - 7] + Theta0(X[t - 15]) + X[t - 16];
+        }
+
+        //
+        // set up working variables.
+        //
+        int     a = H1;
+        int     b = H2;
+        int     c = H3;
+        int     d = H4;
+        int     e = H5;
+        int     f = H6;
+        int     g = H7;
+        int     h = H8;
+
+        int t = 0;     
+        for(int i = 0; i < 8; i ++)
+        {
+            // t = 8 * i
+            h += Sum1(e) + Ch(e, f, g) + K[t] + X[t++];
+            d += h;
+            h += Sum0(a) + Maj(a, b, c);
+
+            // t = 8 * i + 1
+            g += Sum1(d) + Ch(d, e, f) + K[t] + X[t++];
+            c += g;
+            g += Sum0(h) + Maj(h, a, b);
+
+            // t = 8 * i + 2
+            f += Sum1(c) + Ch(c, d, e) + K[t] + X[t++];
+            b += f;
+            f += Sum0(g) + Maj(g, h, a);
+
+            // t = 8 * i + 3
+            e += Sum1(b) + Ch(b, c, d) + K[t] + X[t++];
+            a += e;
+            e += Sum0(f) + Maj(f, g, h);
+
+            // t = 8 * i + 4
+            d += Sum1(a) + Ch(a, b, c) + K[t] + X[t++];
+            h += d;
+            d += Sum0(e) + Maj(e, f, g);
+
+            // t = 8 * i + 5
+            c += Sum1(h) + Ch(h, a, b) + K[t] + X[t++];
+            g += c;
+            c += Sum0(d) + Maj(d, e, f);
+
+            // t = 8 * i + 6
+            b += Sum1(g) + Ch(g, h, a) + K[t] + X[t++];
+            f += b;
+            b += Sum0(c) + Maj(c, d, e);
+
+            // t = 8 * i + 7
+            a += Sum1(f) + Ch(f, g, h) + K[t] + X[t++];
+            e += a;
+            a += Sum0(b) + Maj(b, c, d);
+        }
+
+        H1 += a;
+        H2 += b;
+        H3 += c;
+        H4 += d;
+        H5 += e;
+        H6 += f;
+        H7 += g;
+        H8 += h;
+
+        //
+        // reset the offset and clean out the word buffer.
+        //
+        xOff = 0;
+        for (int i = 0; i < 16; i++)
+        {
+            X[i] = 0;
+        }
+    }
+
+    /* SHA-256 functions */
+    private int Ch(
+        int    x,
+        int    y,
+        int    z)
+    {
+        return (x & y) ^ ((~x) & z);
+    }
+
+    private int Maj(
+        int    x,
+        int    y,
+        int    z)
+    {
+        return (x & y) ^ (x & z) ^ (y & z);
+    }
+
+    private int Sum0(
+        int    x)
+    {
+        return ((x >>> 2) | (x << 30)) ^ ((x >>> 13) | (x << 19)) ^ ((x >>> 22) | (x << 10));
+    }
+
+    private int Sum1(
+        int    x)
+    {
+        return ((x >>> 6) | (x << 26)) ^ ((x >>> 11) | (x << 21)) ^ ((x >>> 25) | (x << 7));
+    }
+
+    private int Theta0(
+        int    x)
+    {
+        return ((x >>> 7) | (x << 25)) ^ ((x >>> 18) | (x << 14)) ^ (x >>> 3);
+    }
+
+    private int Theta1(
+        int    x)
+    {
+        return ((x >>> 17) | (x << 15)) ^ ((x >>> 19) | (x << 13)) ^ (x >>> 10);
+    }
+
+    /* SHA-256 Constants
+     * (represent the first 32 bits of the fractional parts of the
+     * cube roots of the first sixty-four prime numbers)
+     */
+    static final int K[] = {
+        0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+        0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+        0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+        0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+        0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+        0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+        0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+    };
+}
+
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java b/libcore/security/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java
new file mode 100644
index 0000000..e2a9faa
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java
@@ -0,0 +1,85 @@
+package org.bouncycastle.crypto.digests;
+
+
+/**
+ * FIPS 180-2 implementation of SHA-384.
+ *
+ * <pre>
+ *         block  word  digest
+ * SHA-1   512    32    160
+ * SHA-256 512    32    256
+ * SHA-384 1024   64    384
+ * SHA-512 1024   64    512
+ * </pre>
+ */
+public class SHA384Digest
+    extends LongDigest
+{
+
+    private static final int    DIGEST_LENGTH = 48;
+
+    /**
+     * Standard constructor
+     */
+    public SHA384Digest()
+    {
+    }
+
+    /**
+     * Copy constructor.  This will copy the state of the provided
+     * message digest.
+     */
+    public SHA384Digest(SHA384Digest t)
+    {
+        super(t);
+    }
+
+    public String getAlgorithmName()
+    {
+        return "SHA-384";
+    }
+
+    public int getDigestSize()
+    {
+        return DIGEST_LENGTH;
+    }
+
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+    {
+        finish();
+
+        unpackWord(H1, out, outOff);
+        unpackWord(H2, out, outOff + 8);
+        unpackWord(H3, out, outOff + 16);
+        unpackWord(H4, out, outOff + 24);
+        unpackWord(H5, out, outOff + 32);
+        unpackWord(H6, out, outOff + 40);
+
+        reset();
+
+        return DIGEST_LENGTH;
+    }
+
+    /**
+     * reset the chaining variables
+     */
+    public void reset()
+    {
+        super.reset();
+
+        /* SHA-384 initial hash value
+         * The first 64 bits of the fractional parts of the square roots
+         * of the 9th through 16th prime numbers
+         */
+        H1 = 0xcbbb9d5dc1059ed8l;
+        H2 = 0x629a292a367cd507l;
+        H3 = 0x9159015a3070dd17l;
+        H4 = 0x152fecd8f70e5939l;
+        H5 = 0x67332667ffc00b31l;
+        H6 = 0x8eb44a8768581511l;
+        H7 = 0xdb0c2e0d64f98fa7l;
+        H8 = 0x47b5481dbefa4fa4l;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java b/libcore/security/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java
new file mode 100644
index 0000000..1f4ae41
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java
@@ -0,0 +1,87 @@
+package org.bouncycastle.crypto.digests;
+
+
+/**
+ * FIPS 180-2 implementation of SHA-512.
+ *
+ * <pre>
+ *         block  word  digest
+ * SHA-1   512    32    160
+ * SHA-256 512    32    256
+ * SHA-384 1024   64    384
+ * SHA-512 1024   64    512
+ * </pre>
+ */
+public class SHA512Digest
+    extends LongDigest
+{
+    private static final int    DIGEST_LENGTH = 64;
+
+    /**
+     * Standard constructor
+     */
+    public SHA512Digest()
+    {
+    }
+
+    /**
+     * Copy constructor.  This will copy the state of the provided
+     * message digest.
+     */
+    public SHA512Digest(SHA512Digest t)
+    {
+        super(t);
+    }
+
+    public String getAlgorithmName()
+    {
+        return "SHA-512";
+    }
+
+    public int getDigestSize()
+    {
+        return DIGEST_LENGTH;
+    }
+
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+    {
+        finish();
+
+        unpackWord(H1, out, outOff);
+        unpackWord(H2, out, outOff + 8);
+        unpackWord(H3, out, outOff + 16);
+        unpackWord(H4, out, outOff + 24);
+        unpackWord(H5, out, outOff + 32);
+        unpackWord(H6, out, outOff + 40);
+        unpackWord(H7, out, outOff + 48);
+        unpackWord(H8, out, outOff + 56);
+
+        reset();
+
+        return DIGEST_LENGTH;
+    }
+
+    /**
+     * reset the chaining variables
+     */
+    public void reset()
+    {
+        super.reset();
+
+        /* SHA-512 initial hash value
+         * The first 64 bits of the fractional parts of the square roots
+         * of the first eight prime numbers
+         */
+        H1 = 0x6a09e667f3bcc908L;
+        H2 = 0xbb67ae8584caa73bL;
+        H3 = 0x3c6ef372fe94f82bL;
+        H4 = 0xa54ff53a5f1d36f1L;
+        H5 = 0x510e527fade682d1L;
+        H6 = 0x9b05688c2b3e6c1fL;
+        H7 = 0x1f83d9abfb41bd6bL;
+        H8 = 0x5be0cd19137e2179L;
+    }
+}
+
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/digests/ShortenedDigest.java b/libcore/security/src/main/java/org/bouncycastle/crypto/digests/ShortenedDigest.java
new file mode 100644
index 0000000..89033e8
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/digests/ShortenedDigest.java
@@ -0,0 +1,80 @@
+package org.bouncycastle.crypto.digests;
+
+import org.bouncycastle.crypto.ExtendedDigest;
+
+/**
+ * Wrapper class that reduces the output length of a particular digest to
+ * only the first n bytes of the digest function.
+ */
+public class ShortenedDigest 
+    implements ExtendedDigest
+{
+    private ExtendedDigest baseDigest;
+    private int            length;
+    
+    /**
+     * Base constructor.
+     * 
+     * @param baseDigest underlying digest to use.
+     * @param length length in bytes of the output of doFinal.
+     * @exception IllegalArgumentException if baseDigest is null, or length is greater than baseDigest.getDigestSize().
+     */
+    public ShortenedDigest(
+        ExtendedDigest baseDigest,
+        int            length)
+    {
+        if (baseDigest == null)
+        {
+            throw new IllegalArgumentException("baseDigest must not be null");
+        }
+        
+        if (length > baseDigest.getDigestSize())
+        {
+            throw new IllegalArgumentException("baseDigest output not large enough to support length");
+        }
+        
+        this.baseDigest = baseDigest;
+        this.length = length;
+    }
+    
+    public String getAlgorithmName()
+    {
+        return baseDigest.getAlgorithmName() + "(" + length * 8 + ")";
+    }
+
+    public int getDigestSize()
+    {
+        return length;
+    }
+
+    public void update(byte in)
+    {
+        baseDigest.update(in);
+    }
+
+    public void update(byte[] in, int inOff, int len)
+    {
+        baseDigest.update(in, inOff, len);
+    }
+
+    public int doFinal(byte[] out, int outOff)
+    {
+        byte[] tmp = new byte[baseDigest.getDigestSize()];
+        
+        baseDigest.doFinal(tmp, 0);
+        
+        System.arraycopy(tmp, 0, out, outOff, length);
+        
+        return length;
+    }
+
+    public void reset()
+    {
+        baseDigest.reset();
+    }
+
+    public int getByteLength()
+    {
+        return baseDigest.getByteLength();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/encodings/ISO9796d1Encoding.java b/libcore/security/src/main/java/org/bouncycastle/crypto/encodings/ISO9796d1Encoding.java
new file mode 100644
index 0000000..7e30023
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/encodings/ISO9796d1Encoding.java
@@ -0,0 +1,251 @@
+package org.bouncycastle.crypto.encodings;
+
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+
+/**
+ * ISO 9796-1 padding. Note in the light of recent results you should
+ * only use this with RSA (rather than the "simpler" Rabin keys) and you
+ * should never use it with anything other than a hash (ie. even if the 
+ * message is small don't sign the message, sign it's hash) or some "random"
+ * value. See your favorite search engine for details.
+ */
+public class ISO9796d1Encoding
+    implements AsymmetricBlockCipher
+{
+    private static byte[]    shadows = { 0xe, 0x3, 0x5, 0x8, 0x9, 0x4, 0x2, 0xf,
+                                    0x0, 0xd, 0xb, 0x6, 0x7, 0xa, 0xc, 0x1 };
+    private static byte[]    inverse = { 0x8, 0xf, 0x6, 0x1, 0x5, 0x2, 0xb, 0xc,
+                                    0x3, 0x4, 0xd, 0xa, 0xe, 0x9, 0x0, 0x7 };
+
+    private AsymmetricBlockCipher   engine;
+    private boolean                 forEncryption;
+    private int                     bitSize;
+    private int                     padBits = 0;
+
+    public ISO9796d1Encoding(
+        AsymmetricBlockCipher   cipher)
+    {
+        this.engine = cipher;
+    }   
+
+    public AsymmetricBlockCipher getUnderlyingCipher()
+    {
+        return engine;
+    }
+
+    public void init(
+        boolean             forEncryption,
+        CipherParameters    param)
+    {
+        RSAKeyParameters  kParam = null;
+
+        if (param instanceof ParametersWithRandom)
+        {
+            ParametersWithRandom    rParam = (ParametersWithRandom)param;
+
+            kParam = (RSAKeyParameters)rParam.getParameters();
+        }
+        else
+        {
+            kParam = (RSAKeyParameters)param;
+        }
+
+        engine.init(forEncryption, kParam);
+
+        bitSize = kParam.getModulus().bitLength();
+
+        this.forEncryption = forEncryption;
+    }
+
+    /**
+     * return the input block size. The largest message we can process
+     * is (key_size_in_bits + 3)/16, which in our world comes to 
+     * key_size_in_bytes / 2.
+     */
+    public int getInputBlockSize()
+    {
+        int     baseBlockSize = engine.getInputBlockSize();
+
+        if (forEncryption)
+        {
+            return (baseBlockSize + 1) / 2;
+        }
+        else
+        {
+            return baseBlockSize;
+        }
+    }
+
+    /**
+     * return the maximum possible size for the output.
+     */
+    public int getOutputBlockSize()
+    {
+        int     baseBlockSize = engine.getOutputBlockSize();
+
+        if (forEncryption)
+        {
+            return baseBlockSize;
+        }
+        else
+        {
+            return (baseBlockSize + 1) / 2;
+        }
+    }
+
+    /**
+     * set the number of bits in the next message to be treated as 
+     * pad bits.
+     */
+    public void setPadBits(
+        int     padBits)
+    {
+        if (padBits > 7)
+        {
+            throw new IllegalArgumentException("padBits > 7");
+        }
+
+        this.padBits = padBits;
+    }
+
+    /**
+     * retrieve the number of pad bits in the last decoded message.
+     */
+    public int getPadBits()
+    {
+        return padBits;
+    }
+
+    public byte[] processBlock(
+        byte[]  in,
+        int     inOff,
+        int     inLen)
+        throws InvalidCipherTextException
+    {
+        if (forEncryption)
+        {
+            return encodeBlock(in, inOff, inLen);
+        }
+        else
+        {
+            return decodeBlock(in, inOff, inLen);
+        }
+    }
+
+    private byte[] encodeBlock(
+        byte[]  in,
+        int     inOff,
+        int     inLen)
+        throws InvalidCipherTextException
+    {
+        byte[]  block = new byte[(bitSize + 7) / 8];
+        int     r = padBits + 1;
+        int     z = inLen;
+        int     t = (bitSize + 13) / 16;
+
+        for (int i = 0; i < t; i += z)
+        {
+            if (i > t - z)
+            {
+                System.arraycopy(in, inOff + inLen - (t - i),
+                                    block, block.length - t, t - i);
+            }
+            else
+            {
+                System.arraycopy(in, inOff, block, block.length - (i + z), z);
+            }
+        }
+
+        for (int i = block.length - 2 * t; i != block.length; i += 2)
+        {
+            byte    val = block[block.length - t + i / 2];
+            
+            block[i] = (byte)((shadows[(val & 0xff) >>> 4] << 4)
+                                                | shadows[val & 0x0f]);
+            block[i + 1] = val;
+        }
+
+        block[block.length - 2 * z] ^= r;
+        block[block.length - 1] = (byte)((block[block.length - 1] << 4) | 0x06);
+
+        int maxBit = (8 - (bitSize - 1) % 8);
+        int offSet = 0;
+
+        if (maxBit != 8)
+        {
+            block[0] &= 0xff >>> maxBit;
+            block[0] |= 0x80 >>> maxBit;
+        }
+        else
+        {
+            block[0] = 0x00;
+            block[1] |= 0x80;
+            offSet = 1;
+        }
+
+        return engine.processBlock(block, offSet, block.length - offSet);
+    }
+
+    /**
+     * @exception InvalidCipherTextException if the decrypted block is not a valid ISO 9796 bit string
+     */
+    private byte[] decodeBlock(
+        byte[]  in,
+        int     inOff,
+        int     inLen)
+        throws InvalidCipherTextException
+    {
+        byte[]  block = engine.processBlock(in, inOff, inLen);
+        int     r = 1;
+        int     t = (bitSize + 13) / 16;
+
+        if ((block[block.length - 1] & 0x0f) != 0x6)
+        {
+            throw new InvalidCipherTextException("invalid forcing byte in block");
+        }
+
+        block[block.length - 1] = (byte)(((block[block.length - 1] & 0xff) >>> 4) | ((inverse[(block[block.length - 2] & 0xff) >> 4]) << 4));
+        block[0] = (byte)((shadows[(block[1] & 0xff) >>> 4] << 4)
+                                                | shadows[block[1] & 0x0f]);
+
+        boolean boundaryFound = false;
+        int     boundary = 0;
+        
+        for (int i = block.length - 1; i >= block.length - 2 * t; i -= 2)
+        {
+            int val = ((shadows[(block[i] & 0xff) >>> 4] << 4)
+                                        | shadows[block[i] & 0x0f]);
+            
+            if (((block[i - 1] ^ val) & 0xff) != 0)
+            {
+                if (!boundaryFound)
+                {
+                    boundaryFound = true;
+                    r = (block[i - 1] ^ val) & 0xff;
+                    boundary = i - 1;
+                }
+                else
+                {
+                    throw new InvalidCipherTextException("invalid tsums in block");
+                }
+            }
+        }
+
+        block[boundary] = 0;
+
+        byte[]  nblock = new byte[(block.length - boundary) / 2];
+
+        for (int i = 0; i < nblock.length; i++)
+        {
+            nblock[i] = block[2 * i + boundary + 1];
+        }
+
+        padBits = r - 1;
+
+        return nblock;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java b/libcore/security/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java
new file mode 100644
index 0000000..11821a0
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java
@@ -0,0 +1,342 @@
+package org.bouncycastle.crypto.encodings;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+
+/**
+ * Optimal Asymmetric Encryption Padding (OAEP) - see PKCS 1 V 2.
+ */
+public class OAEPEncoding
+    implements AsymmetricBlockCipher
+{
+    private byte[]                  defHash;
+    private Digest                  hash;
+
+    private AsymmetricBlockCipher   engine;
+    private SecureRandom            random;
+    private boolean                 forEncryption;
+
+    public OAEPEncoding(
+        AsymmetricBlockCipher   cipher)
+    {
+        this(cipher, new SHA1Digest(), null);
+    }
+    
+    public OAEPEncoding(
+        AsymmetricBlockCipher       cipher,
+        Digest                      hash)
+    {
+        this(cipher, hash, null);
+    }
+    
+    public OAEPEncoding(
+        AsymmetricBlockCipher       cipher,
+        Digest                      hash,
+        byte[]                      encodingParams)
+    {
+        this.engine = cipher;
+        this.hash = hash;
+        this.defHash = new byte[hash.getDigestSize()];
+        
+        if (encodingParams != null)
+        {
+            hash.update(encodingParams, 0, encodingParams.length);
+        }
+        
+        hash.doFinal(defHash, 0);
+    }
+    
+    public AsymmetricBlockCipher getUnderlyingCipher()
+    {
+        return engine;
+    }
+
+    public void init(
+        boolean             forEncryption,
+        CipherParameters    param)
+    {
+        AsymmetricKeyParameter  kParam;
+
+        if (param instanceof ParametersWithRandom)
+        {
+            ParametersWithRandom  rParam = (ParametersWithRandom)param;
+
+            this.random = rParam.getRandom();
+            kParam = (AsymmetricKeyParameter)rParam.getParameters();
+        }
+        else
+        {   
+            this.random = new SecureRandom();
+            kParam = (AsymmetricKeyParameter)param;
+        }
+
+        engine.init(forEncryption, kParam);
+
+        this.forEncryption = forEncryption;
+    }
+
+    public int getInputBlockSize()
+    {
+        int     baseBlockSize = engine.getInputBlockSize();
+
+        if (forEncryption)
+        {
+            return baseBlockSize - 1 - 2 * defHash.length;
+        }
+        else
+        {
+            return baseBlockSize;
+        }
+    }
+
+    public int getOutputBlockSize()
+    {
+        int     baseBlockSize = engine.getOutputBlockSize();
+
+        if (forEncryption)
+        {
+            return baseBlockSize;
+        }
+        else
+        {
+            return baseBlockSize - 1 - 2 * defHash.length;
+        }
+    }
+
+    public byte[] processBlock(
+        byte[]  in,
+        int     inOff,
+        int     inLen)
+        throws InvalidCipherTextException
+    {
+        if (forEncryption)
+        {
+            return encodeBlock(in, inOff, inLen);
+        }
+        else
+        {
+            return decodeBlock(in, inOff, inLen);
+        }
+    }
+
+    public byte[] encodeBlock(
+        byte[]  in,
+        int     inOff,
+        int     inLen)
+        throws InvalidCipherTextException
+    {
+        byte[]  block = new byte[getInputBlockSize() + 1 + 2 * defHash.length];
+
+        //
+        // copy in the message
+        //
+        System.arraycopy(in, inOff, block, block.length - inLen, inLen);
+
+        //
+        // add sentinel
+        //
+        block[block.length - inLen - 1] = 0x01;
+
+        //
+        // as the block is already zeroed - there's no need to add PS (the >= 0 pad of 0)
+        //
+
+        //
+        // add the hash of the encoding params.
+        //
+        System.arraycopy(defHash, 0, block, defHash.length, defHash.length);
+
+        //
+        // generate the seed.
+        //
+        byte[]  seed = new byte[defHash.length];
+
+        random.nextBytes(seed);
+
+        //
+        // mask the message block.
+        //
+        byte[]  mask = maskGeneratorFunction1(seed, 0, seed.length, block.length - defHash.length);
+
+        for (int i = defHash.length; i != block.length; i++)
+        {
+            block[i] ^= mask[i - defHash.length];
+        }
+
+        //
+        // add in the seed
+        //
+        System.arraycopy(seed, 0, block, 0, defHash.length);
+
+        //
+        // mask the seed.
+        //
+        mask = maskGeneratorFunction1(
+                        block, defHash.length, block.length - defHash.length, defHash.length);
+
+        for (int i = 0; i != defHash.length; i++)
+        {
+            block[i] ^= mask[i];
+        }
+
+        return engine.processBlock(block, 0, block.length);
+    }
+
+    /**
+     * @exception InvalidCipherTextException if the decrypted block turns out to
+     * be badly formatted.
+     */
+    public byte[] decodeBlock(
+        byte[]  in,
+        int     inOff,
+        int     inLen)
+        throws InvalidCipherTextException
+    {
+        byte[]  data = engine.processBlock(in, inOff, inLen);
+        byte[]  block = null;
+
+        //
+        // as we may have zeros in our leading bytes for the block we produced
+        // on encryption, we need to make sure our decrypted block comes back
+        // the same size.
+        //
+        if (data.length < engine.getOutputBlockSize())
+        {
+            block = new byte[engine.getOutputBlockSize()];
+
+            System.arraycopy(data, 0, block, block.length - data.length, data.length);
+        }
+        else
+        {
+            block = data;
+        }
+
+        if (block.length < (2 * defHash.length) + 1)
+        {
+            throw new InvalidCipherTextException("data too short");
+        }
+
+        //
+        // unmask the seed.
+        //
+        byte[] mask = maskGeneratorFunction1(
+                    block, defHash.length, block.length - defHash.length, defHash.length);
+
+        for (int i = 0; i != defHash.length; i++)
+        {
+            block[i] ^= mask[i];
+        }
+
+        //
+        // unmask the message block.
+        //
+        mask = maskGeneratorFunction1(block, 0, defHash.length, block.length - defHash.length);
+
+        for (int i = defHash.length; i != block.length; i++)
+        {
+            block[i] ^= mask[i - defHash.length];
+        }
+
+        //
+        // check the hash of the encoding params.
+        //
+        for (int i = 0; i != defHash.length; i++)
+        {
+            if (defHash[i] != block[defHash.length + i])
+            {
+                throw new InvalidCipherTextException("data hash wrong");
+            }
+        }
+
+        //
+        // find the data block
+        //
+        int start;
+
+        for (start = 2 * defHash.length; start != block.length; start++)
+        {
+            if (block[start] == 1 || block[start] != 0)
+            {
+                break;
+            }
+        }
+
+        if (start >= (block.length - 1) || block[start] != 1)
+        {
+            throw new InvalidCipherTextException("data start wrong " + start);
+        }
+
+        start++;
+
+        //
+        // extract the data block
+        //
+        byte[]  output = new byte[block.length - start];
+
+        System.arraycopy(block, start, output, 0, output.length);
+
+        return output;
+    }
+
+    /**
+     * int to octet string.
+     */
+    private void ItoOSP(
+        int     i,
+        byte[]  sp)
+    {
+        sp[0] = (byte)(i >>> 24);
+        sp[1] = (byte)(i >>> 16);
+        sp[2] = (byte)(i >>> 8);
+        sp[3] = (byte)(i >>> 0);
+    }
+
+    /**
+     * mask generator function, as described in PKCS1v2.
+     */
+    private byte[] maskGeneratorFunction1(
+        byte[]  Z,
+        int     zOff,
+        int     zLen,
+        int     length)
+    {
+        byte[]  mask = new byte[length];
+        byte[]  hashBuf = new byte[defHash.length];
+        byte[]  C = new byte[4];
+        int     counter = 0;
+
+        hash.reset();
+
+        do
+        {
+            ItoOSP(counter, C);
+
+            hash.update(Z, zOff, zLen);
+            hash.update(C, 0, C.length);
+            hash.doFinal(hashBuf, 0);
+
+            System.arraycopy(hashBuf, 0, mask, counter * defHash.length, defHash.length);
+        }
+        while (++counter < (length / defHash.length));
+
+        if ((counter * defHash.length) < length)
+        {
+            ItoOSP(counter, C);
+
+            hash.update(Z, zOff, zLen);
+            hash.update(C, 0, C.length);
+            hash.doFinal(hashBuf, 0);
+
+            System.arraycopy(hashBuf, 0, mask, counter * defHash.length, mask.length - (counter * defHash.length));
+        }
+
+        return mask;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java b/libcore/security/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java
new file mode 100644
index 0000000..09b32eb
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java
@@ -0,0 +1,223 @@
+package org.bouncycastle.crypto.encodings;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+
+/**
+ * this does your basic PKCS 1 v1.5 padding - whether or not you should be using this
+ * depends on your application - see PKCS1 Version 2 for details.
+ */
+public class PKCS1Encoding
+    implements AsymmetricBlockCipher
+{
+    /**
+     * some providers fail to include the leading zero in PKCS1 encoded blocks. If you need to
+     * work with one of these set the system property org.bouncycastle.pkcs1.strict to false.
+     * <p>
+     * The system property is checked during construction of the encoding object, it is set to 
+     * true by default.
+     * </p>
+     */
+    public static String STRICT_LENGTH_ENABLED_PROPERTY = "org.bouncycastle.pkcs1.strict";
+    
+    private static int      HEADER_LENGTH = 10;
+
+    private SecureRandom            random;
+    private AsymmetricBlockCipher   engine;
+    private boolean                 forEncryption;
+    private boolean                 forPrivateKey;
+    private boolean                 useStrictLength;
+
+    /**
+     * Basic constructor.
+     * @param cipher
+     */
+    public PKCS1Encoding(
+        AsymmetricBlockCipher   cipher)
+    {
+        this.engine = cipher;
+        this.useStrictLength = System.getProperty(STRICT_LENGTH_ENABLED_PROPERTY, "true").equals("true");
+    }   
+
+    public AsymmetricBlockCipher getUnderlyingCipher()
+    {
+        return engine;
+    }
+
+    public void init(
+        boolean             forEncryption,
+        CipherParameters    param)
+    {
+        AsymmetricKeyParameter  kParam;
+
+        if (param instanceof ParametersWithRandom)
+        {
+            ParametersWithRandom    rParam = (ParametersWithRandom)param;
+
+            this.random = rParam.getRandom();
+            kParam = (AsymmetricKeyParameter)rParam.getParameters();
+        }
+        else
+        {
+            this.random = new SecureRandom();
+            kParam = (AsymmetricKeyParameter)param;
+        }
+
+        engine.init(forEncryption, kParam);
+
+        this.forPrivateKey = kParam.isPrivate();
+        this.forEncryption = forEncryption;
+    }
+
+    public int getInputBlockSize()
+    {
+        int     baseBlockSize = engine.getInputBlockSize();
+
+        if (forEncryption)
+        {
+            return baseBlockSize - HEADER_LENGTH;
+        }
+        else
+        {
+            return baseBlockSize;
+        }
+    }
+
+    public int getOutputBlockSize()
+    {
+        int     baseBlockSize = engine.getOutputBlockSize();
+
+        if (forEncryption)
+        {
+            return baseBlockSize;
+        }
+        else
+        {
+            return baseBlockSize - HEADER_LENGTH;
+        }
+    }
+
+    public byte[] processBlock(
+        byte[]  in,
+        int     inOff,
+        int     inLen)
+        throws InvalidCipherTextException
+    {
+        if (forEncryption)
+        {
+            return encodeBlock(in, inOff, inLen);
+        }
+        else
+        {
+            return decodeBlock(in, inOff, inLen);
+        }
+    }
+
+    private byte[] encodeBlock(
+        byte[]  in,
+        int     inOff,
+        int     inLen)
+        throws InvalidCipherTextException
+    {
+        byte[]  block = new byte[engine.getInputBlockSize()];
+
+        if (forPrivateKey)
+        {
+            block[0] = 0x01;                        // type code 1
+
+            for (int i = 1; i != block.length - inLen - 1; i++)
+            {
+                block[i] = (byte)0xFF;
+            }
+        }
+        else
+        {
+            random.nextBytes(block);                // random fill
+
+            block[0] = 0x02;                        // type code 2
+
+            //
+            // a zero byte marks the end of the padding, so all
+            // the pad bytes must be non-zero.
+            //
+            for (int i = 1; i != block.length - inLen - 1; i++)
+            {
+                while (block[i] == 0)
+                {
+                    block[i] = (byte)random.nextInt();
+                }
+            }
+        }
+
+        block[block.length - inLen - 1] = 0x00;       // mark the end of the padding
+        System.arraycopy(in, inOff, block, block.length - inLen, inLen);
+
+        return engine.processBlock(block, 0, block.length);
+    }
+
+    /**
+     * @exception InvalidCipherTextException if the decrypted block is not in PKCS1 format.
+     */
+    private byte[] decodeBlock(
+        byte[]  in,
+        int     inOff,
+        int     inLen)
+        throws InvalidCipherTextException
+    {
+        byte[]  block = engine.processBlock(in, inOff, inLen);
+
+        if (block.length < getOutputBlockSize())
+        {
+            throw new InvalidCipherTextException("block truncated");
+        }
+
+        byte type = block[0];
+        
+        if (type != 1 && type != 2)
+        {
+            throw new InvalidCipherTextException("unknown block type");
+        }
+
+        if (useStrictLength && block.length != engine.getOutputBlockSize())
+        {
+            throw new InvalidCipherTextException("block incorrect size");
+        }
+        
+        //
+        // find and extract the message block.
+        //
+        int start;
+        
+        for (start = 1; start != block.length; start++)
+        {
+            byte pad = block[start];
+            
+            if (pad == 0)
+            {
+                break;
+            }
+            if (type == 1 && pad != (byte)0xff)
+            {
+                throw new InvalidCipherTextException("block padding incorrect");
+            }
+        }
+
+        start++;           // data should start at the next byte
+
+        if (start >= block.length || start < HEADER_LENGTH)
+        {
+            throw new InvalidCipherTextException("no data in block");
+        }
+
+        byte[]  result = new byte[block.length - start];
+
+        System.arraycopy(block, start, result, 0, result.length);
+
+        return result;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java b/libcore/security/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java
new file mode 100644
index 0000000..908e78f
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java
@@ -0,0 +1,547 @@
+package org.bouncycastle.crypto.engines;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.KeyParameter;
+
+/**
+ * an implementation of the AES (Rijndael), from FIPS-197.
+ * <p>
+ * For further details see: <a href="http://csrc.nist.gov/encryption/aes/">http://csrc.nist.gov/encryption/aes/</a>.
+ *
+ * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
+ * <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/">http://fp.gladman.plus.com/cryptography_technology/rijndael/</a>
+ *
+ * There are three levels of tradeoff of speed vs memory
+ * Because java has no preprocessor, they are written as three separate classes from which to choose
+ *
+ * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption
+ * and 4 for decryption.
+ *
+ * The middle performance version uses only one 256 word table for each, for a total of 2Kbytes,
+ * adding 12 rotate operations per round to compute the values contained in the other tables from
+ * the contents of the first.
+ *
+ * The slowest version uses no static tables at all and computes the values in each round.
+ * <p>
+ * This file contains the middle performance version with 2Kbytes of static tables for round precomputation.
+ *
+ */
+public class AESEngine
+    implements BlockCipher
+{
+    // The S box
+    private static final byte[] S = {
+        (byte)99, (byte)124, (byte)119, (byte)123, (byte)242, (byte)107, (byte)111, (byte)197,
+        (byte)48,   (byte)1, (byte)103,  (byte)43, (byte)254, (byte)215, (byte)171, (byte)118,
+        (byte)202, (byte)130, (byte)201, (byte)125, (byte)250,  (byte)89,  (byte)71, (byte)240,
+        (byte)173, (byte)212, (byte)162, (byte)175, (byte)156, (byte)164, (byte)114, (byte)192,
+        (byte)183, (byte)253, (byte)147,  (byte)38,  (byte)54,  (byte)63, (byte)247, (byte)204,
+        (byte)52, (byte)165, (byte)229, (byte)241, (byte)113, (byte)216,  (byte)49,  (byte)21,
+        (byte)4, (byte)199,  (byte)35, (byte)195,  (byte)24, (byte)150,   (byte)5, (byte)154,
+        (byte)7,  (byte)18, (byte)128, (byte)226, (byte)235,  (byte)39, (byte)178, (byte)117,
+        (byte)9, (byte)131,  (byte)44,  (byte)26,  (byte)27, (byte)110,  (byte)90, (byte)160,
+        (byte)82,  (byte)59, (byte)214, (byte)179,  (byte)41, (byte)227,  (byte)47, (byte)132,
+        (byte)83, (byte)209,   (byte)0, (byte)237,  (byte)32, (byte)252, (byte)177,  (byte)91,
+        (byte)106, (byte)203, (byte)190,  (byte)57,  (byte)74,  (byte)76,  (byte)88, (byte)207,
+        (byte)208, (byte)239, (byte)170, (byte)251,  (byte)67,  (byte)77,  (byte)51, (byte)133,
+        (byte)69, (byte)249,   (byte)2, (byte)127,  (byte)80,  (byte)60, (byte)159, (byte)168,
+        (byte)81, (byte)163,  (byte)64, (byte)143, (byte)146, (byte)157,  (byte)56, (byte)245,
+        (byte)188, (byte)182, (byte)218,  (byte)33,  (byte)16, (byte)255, (byte)243, (byte)210,
+        (byte)205,  (byte)12,  (byte)19, (byte)236,  (byte)95, (byte)151,  (byte)68,  (byte)23,
+        (byte)196, (byte)167, (byte)126,  (byte)61, (byte)100,  (byte)93,  (byte)25, (byte)115,
+        (byte)96, (byte)129,  (byte)79, (byte)220,  (byte)34,  (byte)42, (byte)144, (byte)136,
+        (byte)70, (byte)238, (byte)184,  (byte)20, (byte)222,  (byte)94,  (byte)11, (byte)219,
+        (byte)224,  (byte)50,  (byte)58,  (byte)10,  (byte)73,   (byte)6,  (byte)36,  (byte)92,
+        (byte)194, (byte)211, (byte)172,  (byte)98, (byte)145, (byte)149, (byte)228, (byte)121,
+        (byte)231, (byte)200,  (byte)55, (byte)109, (byte)141, (byte)213,  (byte)78, (byte)169,
+        (byte)108,  (byte)86, (byte)244, (byte)234, (byte)101, (byte)122, (byte)174,   (byte)8,
+        (byte)186, (byte)120,  (byte)37,  (byte)46,  (byte)28, (byte)166, (byte)180, (byte)198,
+        (byte)232, (byte)221, (byte)116,  (byte)31,  (byte)75, (byte)189, (byte)139, (byte)138,
+        (byte)112,  (byte)62, (byte)181, (byte)102,  (byte)72,   (byte)3, (byte)246,  (byte)14,
+        (byte)97,  (byte)53,  (byte)87, (byte)185, (byte)134, (byte)193,  (byte)29, (byte)158,
+        (byte)225, (byte)248, (byte)152,  (byte)17, (byte)105, (byte)217, (byte)142, (byte)148,
+        (byte)155,  (byte)30, (byte)135, (byte)233, (byte)206,  (byte)85,  (byte)40, (byte)223,
+        (byte)140, (byte)161, (byte)137,  (byte)13, (byte)191, (byte)230,  (byte)66, (byte)104,
+        (byte)65, (byte)153,  (byte)45,  (byte)15, (byte)176,  (byte)84, (byte)187,  (byte)22,
+    };
+
+    // The inverse S-box
+    private static final byte[] Si = {
+        (byte)82,   (byte)9, (byte)106, (byte)213,  (byte)48,  (byte)54, (byte)165,  (byte)56,
+        (byte)191,  (byte)64, (byte)163, (byte)158, (byte)129, (byte)243, (byte)215, (byte)251,
+        (byte)124, (byte)227,  (byte)57, (byte)130, (byte)155,  (byte)47, (byte)255, (byte)135,
+        (byte)52, (byte)142,  (byte)67,  (byte)68, (byte)196, (byte)222, (byte)233, (byte)203,
+        (byte)84, (byte)123, (byte)148,  (byte)50, (byte)166, (byte)194,  (byte)35,  (byte)61,
+        (byte)238,  (byte)76, (byte)149,  (byte)11,  (byte)66, (byte)250, (byte)195,  (byte)78,
+        (byte)8,  (byte)46, (byte)161, (byte)102,  (byte)40, (byte)217,  (byte)36, (byte)178,
+        (byte)118,  (byte)91, (byte)162,  (byte)73, (byte)109, (byte)139, (byte)209,  (byte)37,
+        (byte)114, (byte)248, (byte)246, (byte)100, (byte)134, (byte)104, (byte)152,  (byte)22,
+        (byte)212, (byte)164,  (byte)92, (byte)204,  (byte)93, (byte)101, (byte)182, (byte)146,
+        (byte)108, (byte)112,  (byte)72,  (byte)80, (byte)253, (byte)237, (byte)185, (byte)218,
+        (byte)94,  (byte)21,  (byte)70,  (byte)87, (byte)167, (byte)141, (byte)157, (byte)132,
+        (byte)144, (byte)216, (byte)171,   (byte)0, (byte)140, (byte)188, (byte)211,  (byte)10,
+        (byte)247, (byte)228,  (byte)88,   (byte)5, (byte)184, (byte)179,  (byte)69,   (byte)6,
+        (byte)208,  (byte)44,  (byte)30, (byte)143, (byte)202,  (byte)63,  (byte)15,   (byte)2,
+        (byte)193, (byte)175, (byte)189,   (byte)3,   (byte)1,  (byte)19, (byte)138, (byte)107,
+        (byte)58, (byte)145,  (byte)17,  (byte)65,  (byte)79, (byte)103, (byte)220, (byte)234,
+        (byte)151, (byte)242, (byte)207, (byte)206, (byte)240, (byte)180, (byte)230, (byte)115,
+        (byte)150, (byte)172, (byte)116,  (byte)34, (byte)231, (byte)173,  (byte)53, (byte)133,
+        (byte)226, (byte)249,  (byte)55, (byte)232,  (byte)28, (byte)117, (byte)223, (byte)110,
+        (byte)71, (byte)241,  (byte)26, (byte)113,  (byte)29,  (byte)41, (byte)197, (byte)137,
+        (byte)111, (byte)183,  (byte)98,  (byte)14, (byte)170,  (byte)24, (byte)190,  (byte)27,
+        (byte)252,  (byte)86,  (byte)62,  (byte)75, (byte)198, (byte)210, (byte)121,  (byte)32,
+        (byte)154, (byte)219, (byte)192, (byte)254, (byte)120, (byte)205,  (byte)90, (byte)244,
+        (byte)31, (byte)221, (byte)168,  (byte)51, (byte)136,   (byte)7, (byte)199,  (byte)49,
+        (byte)177,  (byte)18,  (byte)16,  (byte)89,  (byte)39, (byte)128, (byte)236,  (byte)95,
+        (byte)96,  (byte)81, (byte)127, (byte)169,  (byte)25, (byte)181,  (byte)74,  (byte)13,
+        (byte)45, (byte)229, (byte)122, (byte)159, (byte)147, (byte)201, (byte)156, (byte)239,
+        (byte)160, (byte)224,  (byte)59,  (byte)77, (byte)174,  (byte)42, (byte)245, (byte)176,
+        (byte)200, (byte)235, (byte)187,  (byte)60, (byte)131,  (byte)83, (byte)153,  (byte)97,
+        (byte)23,  (byte)43,   (byte)4, (byte)126, (byte)186, (byte)119, (byte)214,  (byte)38,
+        (byte)225, (byte)105,  (byte)20,  (byte)99,  (byte)85,  (byte)33,  (byte)12, (byte)125,
+        };
+
+    // vector used in calculating key schedule (powers of x in GF(256))
+    private static final int[] rcon = {
+         0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
+         0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 };
+
+    // precomputation tables of calculations for rounds
+    private static final int[] T0 =
+    {
+     0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff, 
+     0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102, 
+     0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 
+     0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, 
+     0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, 0xecadad41, 
+     0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, 
+     0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 
+     0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, 
+     0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2, 
+     0x73d8d8ab, 0x53313162, 0x3f15152a, 0x0c040408, 0x52c7c795, 
+     0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a, 
+     0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, 
+     0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912, 
+     0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, 
+     0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 
+     0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, 
+     0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040, 
+     0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d, 
+     0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 
+     0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, 
+     0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a, 
+     0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, 
+     0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080, 
+     0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, 
+     0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, 
+     0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18, 
+     0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488, 
+     0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, 
+     0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0, 
+     0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, 
+     0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 
+     0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, 
+     0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, 
+     0x0a06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd, 
+     0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, 
+     0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, 
+     0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8, 
+     0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, 
+     0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a, 
+     0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, 
+     0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96, 
+     0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c, 
+     0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7, 
+     0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, 
+     0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9, 
+     0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, 
+     0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715, 
+     0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, 
+     0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 
+     0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929, 
+     0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 
+     0x3a16162c};
+
+private static final int[] Tinv0 =
+    {
+     0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b, 
+     0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad, 
+     0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 
+     0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d, 
+     0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03, 
+     0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458, 
+     0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899, 
+     0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, 
+     0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1, 
+     0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f, 
+     0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3, 
+     0x2aab5566, 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3, 
+     0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a, 
+     0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506, 
+     0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05, 
+     0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd, 
+     0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491, 
+     0x055dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6, 
+     0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7, 
+     0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000, 
+     0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd, 
+     0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68, 
+     0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0x0fe75793, 0xd296eeb4, 
+     0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c, 
+     0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0x0b0d090e, 
+     0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af, 
+     0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644, 
+     0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8, 
+     0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85, 
+     0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc, 
+     0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411, 
+     0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322, 
+     0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6, 
+     0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0x0d927850, 
+     0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e, 
+     0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf, 
+     0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x097826cd, 
+     0xf418596e, 0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa, 
+     0x08cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea, 
+     0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235, 
+     0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1, 
+     0xf7daec41, 0x0e50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43, 
+     0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 
+     0x7f516546, 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, 
+     0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a, 
+     0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7, 
+     0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418, 
+     0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478, 
+     0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16, 
+     0x0c25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08, 
+     0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48, 
+     0x4257b8d0};
+
+    private int shift(
+        int     r,
+        int     shift)
+    {
+        return (r >>> shift) | (r << -shift);
+    }
+
+    /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
+
+    private static final int m1 = 0x80808080;
+    private static final int m2 = 0x7f7f7f7f;
+    private static final int m3 = 0x0000001b;
+
+    private int FFmulX(int x)
+    {
+        return (((x & m2) << 1) ^ (((x & m1) >>> 7) * m3));
+    }
+
+    /* 
+       The following defines provide alternative definitions of FFmulX that might
+       give improved performance if a fast 32-bit multiply is not available.
+       
+       private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); } 
+       private static final int  m4 = 0x1b1b1b1b;
+       private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); } 
+
+    */
+
+    private int inv_mcol(int x)
+    {
+        int f2 = FFmulX(x);
+        int f4 = FFmulX(f2);
+        int f8 = FFmulX(f4);
+        int f9 = x ^ f8;
+        
+        return f2 ^ f4 ^ f8 ^ shift(f2 ^ f9, 8) ^ shift(f4 ^ f9, 16) ^ shift(f9, 24);
+    }
+
+    private int subWord(int x)
+    {
+        return (S[x&255]&255 | ((S[(x>>8)&255]&255)<<8) | ((S[(x>>16)&255]&255)<<16) | S[(x>>24)&255]<<24);
+    }
+
+    /**
+     * Calculate the necessary round keys
+     * The number of calculations depends on key size and block size
+     * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
+     * This code is written assuming those are the only possible values
+     */
+    private int[][] generateWorkingKey(
+                                    byte[] key,
+                                    boolean forEncryption)
+    {
+        int         KC = key.length / 4;  // key length in words
+        int         t;
+        
+        if (((KC != 4) && (KC != 6) && (KC != 8)) || ((KC * 4) != key.length))
+        {
+            throw new IllegalArgumentException("Key length not 128/192/256 bits.");
+        }
+
+        ROUNDS = KC + 6;  // This is not always true for the generalized Rijndael that allows larger block sizes
+        int[][] W = new int[ROUNDS+1][4];   // 4 words in a block
+        
+        //
+        // copy the key into the round key array
+        //
+        
+        t = 0;
+        int i = 0;
+        while (i < key.length)
+            {
+                W[t >> 2][t & 3] = (key[i]&0xff) | ((key[i+1]&0xff) << 8) | ((key[i+2]&0xff) << 16) | (key[i+3] << 24);
+                i+=4;
+                t++;
+            }
+        
+        //
+        // while not enough round key material calculated
+        // calculate new values
+        //
+        int k = (ROUNDS + 1) << 2;
+        for (i = KC; (i < k); i++)
+            {
+                int temp = W[(i-1)>>2][(i-1)&3];
+                if ((i % KC) == 0)
+                {
+                    temp = subWord(shift(temp, 8)) ^ rcon[(i / KC)-1];
+                }
+                else if ((KC > 6) && ((i % KC) == 4))
+                {
+                    temp = subWord(temp);
+                }
+                
+                W[i>>2][i&3] = W[(i - KC)>>2][(i-KC)&3] ^ temp;
+            }
+
+        if (!forEncryption)
+        {
+            for (int j = 1; j < ROUNDS; j++)
+            {
+                for (i = 0; i < 4; i++)
+                {
+                    W[j][i] = inv_mcol(W[j][i]);
+                }
+            }
+        }
+
+        return W;
+    }
+
+    private int         ROUNDS;
+    private int[][]     WorkingKey = null;
+    private int         C0, C1, C2, C3;
+    private boolean     forEncryption;
+
+    private static final int BLOCK_SIZE = 16;
+
+    /**
+     * default constructor - 128 bit block size.
+     */
+    public AESEngine()
+    {
+    }
+
+    /**
+     * initialise an AES cipher.
+     *
+     * @param forEncryption whether or not we are for encryption.
+     * @param params the parameters required to set up the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean           forEncryption,
+        CipherParameters  params)
+    {
+        if (params instanceof KeyParameter)
+        {
+            WorkingKey = generateWorkingKey(((KeyParameter)params).getKey(), forEncryption);
+            this.forEncryption = forEncryption;
+            return;
+        }
+
+        throw new IllegalArgumentException("invalid parameter passed to AES init - " + params.getClass().getName());
+    }
+
+    public String getAlgorithmName()
+    {
+        return "AES";
+    }
+
+    public int getBlockSize()
+    {
+        return BLOCK_SIZE;
+    }
+
+    public int processBlock(
+        byte[] in,
+        int inOff,
+        byte[] out,
+        int outOff)
+    {
+        if (WorkingKey == null)
+        {
+            throw new IllegalStateException("AES engine not initialised");
+        }
+
+        if ((inOff + (32 / 2)) > in.length)
+        {
+            throw new DataLengthException("input buffer too short");
+        }
+
+        if ((outOff + (32 / 2)) > out.length)
+        {
+            throw new DataLengthException("output buffer too short");
+        }
+
+        if (forEncryption)
+        {
+            unpackBlock(in, inOff);
+            encryptBlock(WorkingKey);
+            packBlock(out, outOff);
+        }
+        else
+        {
+            unpackBlock(in, inOff);
+            decryptBlock(WorkingKey);
+            packBlock(out, outOff);
+        }
+
+        return BLOCK_SIZE;
+    }
+
+    public void reset()
+    {
+    }
+
+    private final void unpackBlock(
+        byte[]      bytes,
+        int         off)
+    {
+        int     index = off;
+
+        C0 = (bytes[index++] & 0xff);
+        C0 |= (bytes[index++] & 0xff) << 8;
+        C0 |= (bytes[index++] & 0xff) << 16;
+        C0 |= bytes[index++] << 24;
+
+        C1 = (bytes[index++] & 0xff);
+        C1 |= (bytes[index++] & 0xff) << 8;
+        C1 |= (bytes[index++] & 0xff) << 16;
+        C1 |= bytes[index++] << 24;
+
+        C2 = (bytes[index++] & 0xff);
+        C2 |= (bytes[index++] & 0xff) << 8;
+        C2 |= (bytes[index++] & 0xff) << 16;
+        C2 |= bytes[index++] << 24;
+
+        C3 = (bytes[index++] & 0xff);
+        C3 |= (bytes[index++] & 0xff) << 8;
+        C3 |= (bytes[index++] & 0xff) << 16;
+        C3 |= bytes[index++] << 24;
+    }
+
+    private final void packBlock(
+        byte[]      bytes,
+        int         off)
+    {
+        int     index = off;
+
+        bytes[index++] = (byte)C0;
+        bytes[index++] = (byte)(C0 >> 8);
+        bytes[index++] = (byte)(C0 >> 16);
+        bytes[index++] = (byte)(C0 >> 24);
+
+        bytes[index++] = (byte)C1;
+        bytes[index++] = (byte)(C1 >> 8);
+        bytes[index++] = (byte)(C1 >> 16);
+        bytes[index++] = (byte)(C1 >> 24);
+
+        bytes[index++] = (byte)C2;
+        bytes[index++] = (byte)(C2 >> 8);
+        bytes[index++] = (byte)(C2 >> 16);
+        bytes[index++] = (byte)(C2 >> 24);
+
+        bytes[index++] = (byte)C3;
+        bytes[index++] = (byte)(C3 >> 8);
+        bytes[index++] = (byte)(C3 >> 16);
+        bytes[index++] = (byte)(C3 >> 24);
+    }
+
+
+    private final void encryptBlock(int[][] KW)
+    {
+        int r, r0, r1, r2, r3;
+
+        C0 ^= KW[0][0];
+        C1 ^= KW[0][1];
+        C2 ^= KW[0][2];
+        C3 ^= KW[0][3];
+
+        r = 1;
+
+        while (r < ROUNDS - 1)
+        {
+            r0 = T0[C0&255] ^ shift(T0[(C1>>8)&255], 24) ^ shift(T0[(C2>>16)&255],16) ^ shift(T0[(C3>>24)&255],8) ^ KW[r][0];
+            r1 = T0[C1&255] ^ shift(T0[(C2>>8)&255], 24) ^ shift(T0[(C3>>16)&255], 16) ^ shift(T0[(C0>>24)&255], 8) ^ KW[r][1];
+            r2 = T0[C2&255] ^ shift(T0[(C3>>8)&255], 24) ^ shift(T0[(C0>>16)&255], 16) ^ shift(T0[(C1>>24)&255], 8) ^ KW[r][2];
+            r3 = T0[C3&255] ^ shift(T0[(C0>>8)&255], 24) ^ shift(T0[(C1>>16)&255], 16) ^ shift(T0[(C2>>24)&255], 8) ^ KW[r++][3];
+            C0 = T0[r0&255] ^ shift(T0[(r1>>8)&255], 24) ^ shift(T0[(r2>>16)&255], 16) ^ shift(T0[(r3>>24)&255], 8) ^ KW[r][0];
+            C1 = T0[r1&255] ^ shift(T0[(r2>>8)&255], 24) ^ shift(T0[(r3>>16)&255], 16) ^ shift(T0[(r0>>24)&255], 8) ^ KW[r][1];
+            C2 = T0[r2&255] ^ shift(T0[(r3>>8)&255], 24) ^ shift(T0[(r0>>16)&255], 16) ^ shift(T0[(r1>>24)&255], 8) ^ KW[r][2];
+            C3 = T0[r3&255] ^ shift(T0[(r0>>8)&255], 24) ^ shift(T0[(r1>>16)&255], 16) ^ shift(T0[(r2>>24)&255], 8) ^ KW[r++][3];
+        }
+
+        r0 = T0[C0&255] ^ shift(T0[(C1>>8)&255], 24) ^ shift(T0[(C2>>16)&255], 16) ^ shift(T0[(C3>>24)&255], 8) ^ KW[r][0];
+        r1 = T0[C1&255] ^ shift(T0[(C2>>8)&255], 24) ^ shift(T0[(C3>>16)&255], 16) ^ shift(T0[(C0>>24)&255], 8) ^ KW[r][1];
+        r2 = T0[C2&255] ^ shift(T0[(C3>>8)&255], 24) ^ shift(T0[(C0>>16)&255], 16) ^ shift(T0[(C1>>24)&255], 8) ^ KW[r][2];
+        r3 = T0[C3&255] ^ shift(T0[(C0>>8)&255], 24) ^ shift(T0[(C1>>16)&255], 16) ^ shift(T0[(C2>>24)&255], 8) ^ KW[r++][3];
+
+        // the final round's table is a simple function of S so we don't use a whole other four tables for it
+
+        C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r][0];
+        C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r][1];
+        C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r][2];
+        C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r][3];
+
+    }
+
+    private final void decryptBlock(int[][] KW)
+    {
+        int r, r0, r1, r2, r3;
+
+        C0 ^= KW[ROUNDS][0];
+        C1 ^= KW[ROUNDS][1];
+        C2 ^= KW[ROUNDS][2];
+        C3 ^= KW[ROUNDS][3];
+
+        r = ROUNDS-1;
+
+        while (r>1)
+        {
+            r0 = Tinv0[C0&255] ^ shift(Tinv0[(C3>>8)&255], 24) ^ shift(Tinv0[(C2>>16)&255], 16) ^ shift(Tinv0[(C1>>24)&255], 8) ^ KW[r][0];
+            r1 = Tinv0[C1&255] ^ shift(Tinv0[(C0>>8)&255], 24) ^ shift(Tinv0[(C3>>16)&255], 16) ^ shift(Tinv0[(C2>>24)&255], 8) ^ KW[r][1];
+            r2 = Tinv0[C2&255] ^ shift(Tinv0[(C1>>8)&255], 24) ^ shift(Tinv0[(C0>>16)&255], 16) ^ shift(Tinv0[(C3>>24)&255], 8) ^ KW[r][2];
+            r3 = Tinv0[C3&255] ^ shift(Tinv0[(C2>>8)&255], 24) ^ shift(Tinv0[(C1>>16)&255], 16) ^ shift(Tinv0[(C0>>24)&255], 8) ^ KW[r--][3];
+            C0 = Tinv0[r0&255] ^ shift(Tinv0[(r3>>8)&255], 24) ^ shift(Tinv0[(r2>>16)&255], 16) ^ shift(Tinv0[(r1>>24)&255], 8) ^ KW[r][0];
+            C1 = Tinv0[r1&255] ^ shift(Tinv0[(r0>>8)&255], 24) ^ shift(Tinv0[(r3>>16)&255], 16) ^ shift(Tinv0[(r2>>24)&255], 8) ^ KW[r][1];
+            C2 = Tinv0[r2&255] ^ shift(Tinv0[(r1>>8)&255], 24) ^ shift(Tinv0[(r0>>16)&255], 16) ^ shift(Tinv0[(r3>>24)&255], 8) ^ KW[r][2];
+            C3 = Tinv0[r3&255] ^ shift(Tinv0[(r2>>8)&255], 24) ^ shift(Tinv0[(r1>>16)&255], 16) ^ shift(Tinv0[(r0>>24)&255], 8) ^ KW[r--][3];
+        }
+
+        r0 = Tinv0[C0&255] ^ shift(Tinv0[(C3>>8)&255], 24) ^ shift(Tinv0[(C2>>16)&255], 16) ^ shift(Tinv0[(C1>>24)&255], 8) ^ KW[r][0];
+        r1 = Tinv0[C1&255] ^ shift(Tinv0[(C0>>8)&255], 24) ^ shift(Tinv0[(C3>>16)&255], 16) ^ shift(Tinv0[(C2>>24)&255], 8) ^ KW[r][1];
+        r2 = Tinv0[C2&255] ^ shift(Tinv0[(C1>>8)&255], 24) ^ shift(Tinv0[(C0>>16)&255], 16) ^ shift(Tinv0[(C3>>24)&255], 8) ^ KW[r][2];
+        r3 = Tinv0[C3&255] ^ shift(Tinv0[(C2>>8)&255], 24) ^ shift(Tinv0[(C1>>16)&255], 16) ^ shift(Tinv0[(C0>>24)&255], 8) ^ KW[r--][3];
+        
+        // the final round's table is a simple function of Si so we don't use a whole other four tables for it
+
+        C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0][0];
+        C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0][1];
+        C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0][2];
+        C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0][3];
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java b/libcore/security/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java
new file mode 100644
index 0000000..e693a1b
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java
@@ -0,0 +1,876 @@
+package org.bouncycastle.crypto.engines;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.KeyParameter;
+
+/**
+ * an implementation of the AES (Rijndael), from FIPS-197.
+ * <p>
+ * For further details see: <a href="http://csrc.nist.gov/encryption/aes/">http://csrc.nist.gov/encryption/aes/</a>.
+ *
+ * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
+ * <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/">http://fp.gladman.plus.com/cryptography_technology/rijndael/</a>
+ *
+ * There are three levels of tradeoff of speed vs memory
+ * Because java has no preprocessor, they are written as three separate classes from which to choose
+ *
+ * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption
+ * and 4 for decryption.
+ *
+ * The middle performance version uses only one 256 word table for each, for a total of 2Kbytes,
+ * adding 12 rotate operations per round to compute the values contained in the other tables from
+ * the contents of the first
+ *
+ * The slowest version uses no static tables at all and computes the values in each round
+ * <p>
+ * This file contains the fast version with 8Kbytes of static tables for round precomputation
+ *
+ */
+public class AESFastEngine
+    implements BlockCipher
+{
+    // The S box
+    private static final byte[] S = {
+        (byte)99, (byte)124, (byte)119, (byte)123, (byte)242, (byte)107, (byte)111, (byte)197,
+        (byte)48,   (byte)1, (byte)103,  (byte)43, (byte)254, (byte)215, (byte)171, (byte)118,
+        (byte)202, (byte)130, (byte)201, (byte)125, (byte)250,  (byte)89,  (byte)71, (byte)240,
+        (byte)173, (byte)212, (byte)162, (byte)175, (byte)156, (byte)164, (byte)114, (byte)192,
+        (byte)183, (byte)253, (byte)147,  (byte)38,  (byte)54,  (byte)63, (byte)247, (byte)204,
+        (byte)52, (byte)165, (byte)229, (byte)241, (byte)113, (byte)216,  (byte)49,  (byte)21,
+        (byte)4, (byte)199,  (byte)35, (byte)195,  (byte)24, (byte)150,   (byte)5, (byte)154,
+        (byte)7,  (byte)18, (byte)128, (byte)226, (byte)235,  (byte)39, (byte)178, (byte)117,
+        (byte)9, (byte)131,  (byte)44,  (byte)26,  (byte)27, (byte)110,  (byte)90, (byte)160,
+        (byte)82,  (byte)59, (byte)214, (byte)179,  (byte)41, (byte)227,  (byte)47, (byte)132,
+        (byte)83, (byte)209,   (byte)0, (byte)237,  (byte)32, (byte)252, (byte)177,  (byte)91,
+        (byte)106, (byte)203, (byte)190,  (byte)57,  (byte)74,  (byte)76,  (byte)88, (byte)207,
+        (byte)208, (byte)239, (byte)170, (byte)251,  (byte)67,  (byte)77,  (byte)51, (byte)133,
+        (byte)69, (byte)249,   (byte)2, (byte)127,  (byte)80,  (byte)60, (byte)159, (byte)168,
+        (byte)81, (byte)163,  (byte)64, (byte)143, (byte)146, (byte)157,  (byte)56, (byte)245,
+        (byte)188, (byte)182, (byte)218,  (byte)33,  (byte)16, (byte)255, (byte)243, (byte)210,
+        (byte)205,  (byte)12,  (byte)19, (byte)236,  (byte)95, (byte)151,  (byte)68,  (byte)23,
+        (byte)196, (byte)167, (byte)126,  (byte)61, (byte)100,  (byte)93,  (byte)25, (byte)115,
+        (byte)96, (byte)129,  (byte)79, (byte)220,  (byte)34,  (byte)42, (byte)144, (byte)136,
+        (byte)70, (byte)238, (byte)184,  (byte)20, (byte)222,  (byte)94,  (byte)11, (byte)219,
+        (byte)224,  (byte)50,  (byte)58,  (byte)10,  (byte)73,   (byte)6,  (byte)36,  (byte)92,
+        (byte)194, (byte)211, (byte)172,  (byte)98, (byte)145, (byte)149, (byte)228, (byte)121,
+        (byte)231, (byte)200,  (byte)55, (byte)109, (byte)141, (byte)213,  (byte)78, (byte)169,
+        (byte)108,  (byte)86, (byte)244, (byte)234, (byte)101, (byte)122, (byte)174,   (byte)8,
+        (byte)186, (byte)120,  (byte)37,  (byte)46,  (byte)28, (byte)166, (byte)180, (byte)198,
+        (byte)232, (byte)221, (byte)116,  (byte)31,  (byte)75, (byte)189, (byte)139, (byte)138,
+        (byte)112,  (byte)62, (byte)181, (byte)102,  (byte)72,   (byte)3, (byte)246,  (byte)14,
+        (byte)97,  (byte)53,  (byte)87, (byte)185, (byte)134, (byte)193,  (byte)29, (byte)158,
+        (byte)225, (byte)248, (byte)152,  (byte)17, (byte)105, (byte)217, (byte)142, (byte)148,
+        (byte)155,  (byte)30, (byte)135, (byte)233, (byte)206,  (byte)85,  (byte)40, (byte)223,
+        (byte)140, (byte)161, (byte)137,  (byte)13, (byte)191, (byte)230,  (byte)66, (byte)104,
+        (byte)65, (byte)153,  (byte)45,  (byte)15, (byte)176,  (byte)84, (byte)187,  (byte)22,
+    };
+
+    // The inverse S-box
+    private static final byte[] Si = {
+        (byte)82,   (byte)9, (byte)106, (byte)213,  (byte)48,  (byte)54, (byte)165,  (byte)56,
+        (byte)191,  (byte)64, (byte)163, (byte)158, (byte)129, (byte)243, (byte)215, (byte)251,
+        (byte)124, (byte)227,  (byte)57, (byte)130, (byte)155,  (byte)47, (byte)255, (byte)135,
+        (byte)52, (byte)142,  (byte)67,  (byte)68, (byte)196, (byte)222, (byte)233, (byte)203,
+        (byte)84, (byte)123, (byte)148,  (byte)50, (byte)166, (byte)194,  (byte)35,  (byte)61,
+        (byte)238,  (byte)76, (byte)149,  (byte)11,  (byte)66, (byte)250, (byte)195,  (byte)78,
+        (byte)8,  (byte)46, (byte)161, (byte)102,  (byte)40, (byte)217,  (byte)36, (byte)178,
+        (byte)118,  (byte)91, (byte)162,  (byte)73, (byte)109, (byte)139, (byte)209,  (byte)37,
+        (byte)114, (byte)248, (byte)246, (byte)100, (byte)134, (byte)104, (byte)152,  (byte)22,
+        (byte)212, (byte)164,  (byte)92, (byte)204,  (byte)93, (byte)101, (byte)182, (byte)146,
+        (byte)108, (byte)112,  (byte)72,  (byte)80, (byte)253, (byte)237, (byte)185, (byte)218,
+        (byte)94,  (byte)21,  (byte)70,  (byte)87, (byte)167, (byte)141, (byte)157, (byte)132,
+        (byte)144, (byte)216, (byte)171,   (byte)0, (byte)140, (byte)188, (byte)211,  (byte)10,
+        (byte)247, (byte)228,  (byte)88,   (byte)5, (byte)184, (byte)179,  (byte)69,   (byte)6,
+        (byte)208,  (byte)44,  (byte)30, (byte)143, (byte)202,  (byte)63,  (byte)15,   (byte)2,
+        (byte)193, (byte)175, (byte)189,   (byte)3,   (byte)1,  (byte)19, (byte)138, (byte)107,
+        (byte)58, (byte)145,  (byte)17,  (byte)65,  (byte)79, (byte)103, (byte)220, (byte)234,
+        (byte)151, (byte)242, (byte)207, (byte)206, (byte)240, (byte)180, (byte)230, (byte)115,
+        (byte)150, (byte)172, (byte)116,  (byte)34, (byte)231, (byte)173,  (byte)53, (byte)133,
+        (byte)226, (byte)249,  (byte)55, (byte)232,  (byte)28, (byte)117, (byte)223, (byte)110,
+        (byte)71, (byte)241,  (byte)26, (byte)113,  (byte)29,  (byte)41, (byte)197, (byte)137,
+        (byte)111, (byte)183,  (byte)98,  (byte)14, (byte)170,  (byte)24, (byte)190,  (byte)27,
+        (byte)252,  (byte)86,  (byte)62,  (byte)75, (byte)198, (byte)210, (byte)121,  (byte)32,
+        (byte)154, (byte)219, (byte)192, (byte)254, (byte)120, (byte)205,  (byte)90, (byte)244,
+        (byte)31, (byte)221, (byte)168,  (byte)51, (byte)136,   (byte)7, (byte)199,  (byte)49,
+        (byte)177,  (byte)18,  (byte)16,  (byte)89,  (byte)39, (byte)128, (byte)236,  (byte)95,
+        (byte)96,  (byte)81, (byte)127, (byte)169,  (byte)25, (byte)181,  (byte)74,  (byte)13,
+        (byte)45, (byte)229, (byte)122, (byte)159, (byte)147, (byte)201, (byte)156, (byte)239,
+        (byte)160, (byte)224,  (byte)59,  (byte)77, (byte)174,  (byte)42, (byte)245, (byte)176,
+        (byte)200, (byte)235, (byte)187,  (byte)60, (byte)131,  (byte)83, (byte)153,  (byte)97,
+        (byte)23,  (byte)43,   (byte)4, (byte)126, (byte)186, (byte)119, (byte)214,  (byte)38,
+        (byte)225, (byte)105,  (byte)20,  (byte)99,  (byte)85,  (byte)33,  (byte)12, (byte)125,
+        };
+
+    // vector used in calculating key schedule (powers of x in GF(256))
+    private static final int[] rcon = {
+         0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
+         0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 };
+
+    // precomputation tables of calculations for rounds
+    private static final int[] T0 =
+    {
+     0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff, 
+     0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102, 
+     0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 
+     0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, 
+     0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, 0xecadad41, 
+     0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, 
+     0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 
+     0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, 
+     0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2, 
+     0x73d8d8ab, 0x53313162, 0x3f15152a, 0x0c040408, 0x52c7c795, 
+     0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a, 
+     0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, 
+     0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912, 
+     0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, 
+     0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 
+     0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, 
+     0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040, 
+     0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d, 
+     0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 
+     0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, 
+     0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a, 
+     0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, 
+     0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080, 
+     0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, 
+     0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, 
+     0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18, 
+     0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488, 
+     0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, 
+     0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0, 
+     0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, 
+     0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 
+     0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, 
+     0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, 
+     0x0a06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd, 
+     0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, 
+     0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, 
+     0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8, 
+     0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, 
+     0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a, 
+     0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, 
+     0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96, 
+     0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c, 
+     0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7, 
+     0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, 
+     0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9, 
+     0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, 
+     0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715, 
+     0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, 
+     0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 
+     0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929, 
+     0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 
+     0x3a16162c};
+
+    private static final int[] T1 =
+    {
+     0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d, 
+     0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, 0x30306050, 0x01010203, 
+     0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6, 
+     0x7676ec9a, 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, 
+     0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, 0xadad41ec, 
+     0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, 0x9c9c23bf, 0xa4a453f7, 
+     0x7272e496, 0xc0c09b5b, 0xb7b775c2, 0xfdfde11c, 0x93933dae, 
+     0x26264c6a, 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, 
+     0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, 0x7171e293, 
+     0xd8d8ab73, 0x31316253, 0x15152a3f, 0x0404080c, 0xc7c79552, 
+     0x23234665, 0xc3c39d5e, 0x18183028, 0x969637a1, 0x05050a0f, 
+     0x9a9a2fb5, 0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, 
+     0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, 0x0909121b, 
+     0x83831d9e, 0x2c2c5874, 0x1a1a342e, 0x1b1b362d, 0x6e6edcb2, 
+     0x5a5ab4ee, 0xa0a05bfb, 0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 
+     0xb3b37dce, 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397, 
+     0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, 0x20204060, 
+     0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, 0x6a6ad4be, 0xcbcb8d46, 
+     0xbebe67d9, 0x3939724b, 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 
+     0xcfcf854a, 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, 
+     0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, 0x45458acf, 
+     0xf9f9e910, 0x02020406, 0x7f7ffe81, 0x5050a0f0, 0x3c3c7844, 
+     0x9f9f25ba, 0xa8a84be3, 0x5151a2f3, 0xa3a35dfe, 0x404080c0, 
+     0x8f8f058a, 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, 
+     0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, 0x10102030, 
+     0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, 0xcdcd814c, 0x0c0c1814, 
+     0x13132635, 0xececc32f, 0x5f5fbee1, 0x979735a2, 0x444488cc, 
+     0x17172e39, 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, 
+     0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, 0x6060c0a0, 
+     0x81811998, 0x4f4f9ed1, 0xdcdca37f, 0x22224466, 0x2a2a547e, 
+     0x90903bab, 0x88880b83, 0x46468cca, 0xeeeec729, 0xb8b86bd3, 
+     0x1414283c, 0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76, 
+     0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, 0x494992db, 
+     0x06060c0a, 0x2424486c, 0x5c5cb8e4, 0xc2c29f5d, 0xd3d3bd6e, 
+     0xacac43ef, 0x6262c4a6, 0x919139a8, 0x959531a4, 0xe4e4d337, 
+     0x7979f28b, 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7, 
+     0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, 0x6c6cd8b4, 
+     0x5656acfa, 0xf4f4f307, 0xeaeacf25, 0x6565caaf, 0x7a7af48e, 
+     0xaeae47e9, 0x08081018, 0xbaba6fd5, 0x7878f088, 0x25254a6f, 
+     0x2e2e5c72, 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, 
+     0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, 0x4b4b96dd, 
+     0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, 0x7070e090, 0x3e3e7c42, 
+     0xb5b571c4, 0x6666ccaa, 0x484890d8, 0x03030605, 0xf6f6f701, 
+     0x0e0e1c12, 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, 
+     0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, 0xe1e1d938, 
+     0xf8f8eb13, 0x98982bb3, 0x11112233, 0x6969d2bb, 0xd9d9a970, 
+     0x8e8e0789, 0x949433a7, 0x9b9b2db6, 0x1e1e3c22, 0x87871592, 
+     0xe9e9c920, 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a, 
+     0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, 0xbfbf65da, 
+     0xe6e6d731, 0x424284c6, 0x6868d0b8, 0x414182c3, 0x999929b0, 
+     0x2d2d5a77, 0x0f0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 
+     0x16162c3a};
+
+    private static final int[] T2 =
+    {
+     0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2, 
+     0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, 0x30605030, 0x01020301, 
+     0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab, 
+     0x76ec9a76, 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, 
+     0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, 0xad41ecad, 
+     0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, 0x9c23bf9c, 0xa453f7a4, 
+     0x72e49672, 0xc09b5bc0, 0xb775c2b7, 0xfde11cfd, 0x933dae93, 
+     0x264c6a26, 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, 
+     0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, 0x71e29371, 
+     0xd8ab73d8, 0x31625331, 0x152a3f15, 0x04080c04, 0xc79552c7, 
+     0x23466523, 0xc39d5ec3, 0x18302818, 0x9637a196, 0x050a0f05, 
+     0x9a2fb59a, 0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, 
+     0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, 0x09121b09, 
+     0x831d9e83, 0x2c58742c, 0x1a342e1a, 0x1b362d1b, 0x6edcb26e, 
+     0x5ab4ee5a, 0xa05bfba0, 0x52a4f652, 0x3b764d3b, 0xd6b761d6, 
+     0xb37dceb3, 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784, 
+     0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, 0x20406020, 
+     0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, 0x6ad4be6a, 0xcb8d46cb, 
+     0xbe67d9be, 0x39724b39, 0x4a94de4a, 0x4c98d44c, 0x58b0e858, 
+     0xcf854acf, 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, 
+     0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, 0x458acf45, 
+     0xf9e910f9, 0x02040602, 0x7ffe817f, 0x50a0f050, 0x3c78443c, 
+     0x9f25ba9f, 0xa84be3a8, 0x51a2f351, 0xa35dfea3, 0x4080c040, 
+     0x8f058a8f, 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, 
+     0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, 0x10203010, 
+     0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, 0xcd814ccd, 0x0c18140c, 
+     0x13263513, 0xecc32fec, 0x5fbee15f, 0x9735a297, 0x4488cc44, 
+     0x172e3917, 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, 
+     0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, 0x60c0a060, 
+     0x81199881, 0x4f9ed14f, 0xdca37fdc, 0x22446622, 0x2a547e2a, 
+     0x903bab90, 0x880b8388, 0x468cca46, 0xeec729ee, 0xb86bd3b8, 
+     0x14283c14, 0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db, 
+     0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, 0x4992db49, 
+     0x060c0a06, 0x24486c24, 0x5cb8e45c, 0xc29f5dc2, 0xd3bd6ed3, 
+     0xac43efac, 0x62c4a662, 0x9139a891, 0x9531a495, 0xe4d337e4, 
+     0x79f28b79, 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d, 
+     0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, 0x6cd8b46c, 
+     0x56acfa56, 0xf4f307f4, 0xeacf25ea, 0x65caaf65, 0x7af48e7a, 
+     0xae47e9ae, 0x08101808, 0xba6fd5ba, 0x78f08878, 0x254a6f25, 
+     0x2e5c722e, 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, 
+     0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, 0x4b96dd4b, 
+     0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, 0x70e09070, 0x3e7c423e, 
+     0xb571c4b5, 0x66ccaa66, 0x4890d848, 0x03060503, 0xf6f701f6, 
+     0x0e1c120e, 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, 
+     0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, 0xe1d938e1, 
+     0xf8eb13f8, 0x982bb398, 0x11223311, 0x69d2bb69, 0xd9a970d9, 
+     0x8e07898e, 0x9433a794, 0x9b2db69b, 0x1e3c221e, 0x87159287, 
+     0xe9c920e9, 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf, 
+     0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, 0xbf65dabf, 
+     0xe6d731e6, 0x4284c642, 0x68d0b868, 0x4182c341, 0x9929b099, 
+     0x2d5a772d, 0x0f1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 
+     0x162c3a16};
+
+    private static final int[] T3 =
+    {
+     0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2, 
+     0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, 0x60503030, 0x02030101, 
+     0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab, 
+     0xec9a7676, 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, 
+     0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, 0x41ecadad, 
+     0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, 0x23bf9c9c, 0x53f7a4a4, 
+     0xe4967272, 0x9b5bc0c0, 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 
+     0x4c6a2626, 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, 
+     0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, 0xe2937171, 
+     0xab73d8d8, 0x62533131, 0x2a3f1515, 0x080c0404, 0x9552c7c7, 
+     0x46652323, 0x9d5ec3c3, 0x30281818, 0x37a19696, 0x0a0f0505, 
+     0x2fb59a9a, 0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, 
+     0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, 0x121b0909, 
+     0x1d9e8383, 0x58742c2c, 0x342e1a1a, 0x362d1b1b, 0xdcb26e6e, 
+     0xb4ee5a5a, 0x5bfba0a0, 0xa4f65252, 0x764d3b3b, 0xb761d6d6, 
+     0x7dceb3b3, 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484, 
+     0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, 0x40602020, 
+     0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, 0xd4be6a6a, 0x8d46cbcb, 
+     0x67d9bebe, 0x724b3939, 0x94de4a4a, 0x98d44c4c, 0xb0e85858, 
+     0x854acfcf, 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, 
+     0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, 0x8acf4545, 
+     0xe910f9f9, 0x04060202, 0xfe817f7f, 0xa0f05050, 0x78443c3c, 
+     0x25ba9f9f, 0x4be3a8a8, 0xa2f35151, 0x5dfea3a3, 0x80c04040, 
+     0x058a8f8f, 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, 
+     0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, 0x20301010, 
+     0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, 0x814ccdcd, 0x18140c0c, 
+     0x26351313, 0xc32fecec, 0xbee15f5f, 0x35a29797, 0x88cc4444, 
+     0x2e391717, 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, 
+     0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, 0xc0a06060, 
+     0x19988181, 0x9ed14f4f, 0xa37fdcdc, 0x44662222, 0x547e2a2a, 
+     0x3bab9090, 0x0b838888, 0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 
+     0x283c1414, 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb, 
+     0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, 0x92db4949, 
+     0x0c0a0606, 0x486c2424, 0xb8e45c5c, 0x9f5dc2c2, 0xbd6ed3d3, 
+     0x43efacac, 0xc4a66262, 0x39a89191, 0x31a49595, 0xd337e4e4, 
+     0xf28b7979, 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d, 
+     0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, 0xd8b46c6c, 
+     0xacfa5656, 0xf307f4f4, 0xcf25eaea, 0xcaaf6565, 0xf48e7a7a, 
+     0x47e9aeae, 0x10180808, 0x6fd5baba, 0xf0887878, 0x4a6f2525, 
+     0x5c722e2e, 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, 
+     0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, 0x96dd4b4b, 
+     0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, 0xe0907070, 0x7c423e3e, 
+     0x71c4b5b5, 0xccaa6666, 0x90d84848, 0x06050303, 0xf701f6f6, 
+     0x1c120e0e, 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, 
+     0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, 0xd938e1e1, 
+     0xeb13f8f8, 0x2bb39898, 0x22331111, 0xd2bb6969, 0xa970d9d9, 
+     0x07898e8e, 0x33a79494, 0x2db69b9b, 0x3c221e1e, 0x15928787, 
+     0xc920e9e9, 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf, 
+     0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, 0x65dabfbf, 
+     0xd731e6e6, 0x84c64242, 0xd0b86868, 0x82c34141, 0x29b09999, 
+     0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 
+     0x2c3a1616};
+
+private static final int[] Tinv0 =
+    {
+     0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b, 
+     0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad, 
+     0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 
+     0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d, 
+     0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03, 
+     0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458, 
+     0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899, 
+     0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, 
+     0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1, 
+     0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f, 
+     0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3, 
+     0x2aab5566, 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3, 
+     0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a, 
+     0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506, 
+     0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05, 
+     0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd, 
+     0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491, 
+     0x055dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6, 
+     0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7, 
+     0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000, 
+     0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd, 
+     0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68, 
+     0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0x0fe75793, 0xd296eeb4, 
+     0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c, 
+     0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0x0b0d090e, 
+     0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af, 
+     0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644, 
+     0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8, 
+     0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85, 
+     0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc, 
+     0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411, 
+     0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322, 
+     0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6, 
+     0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0x0d927850, 
+     0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e, 
+     0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf, 
+     0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x097826cd, 
+     0xf418596e, 0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa, 
+     0x08cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea, 
+     0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235, 
+     0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1, 
+     0xf7daec41, 0x0e50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43, 
+     0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 
+     0x7f516546, 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, 
+     0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a, 
+     0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7, 
+     0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418, 
+     0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478, 
+     0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16, 
+     0x0c25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08, 
+     0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48, 
+     0x4257b8d0};
+
+    private static final int[] Tinv1 =
+    {
+     0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, 0x6bab3bcb, 
+     0x459d1ff1, 0x58faacab, 0x03e34b93, 0xfa302055, 0x6d76adf6, 
+     0x76cc8891, 0x4c02f525, 0xd7e54ffc, 0xcb2ac5d7, 0x44352680, 
+     0xa362b58f, 0x5ab1de49, 0x1bba2567, 0x0eea4598, 0xc0fe5de1, 
+     0x752fc302, 0xf04c8112, 0x97468da3, 0xf9d36bc6, 0x5f8f03e7, 
+     0x9c921595, 0x7a6dbfeb, 0x595295da, 0x83bed42d, 0x217458d3, 
+     0x69e04929, 0xc8c98e44, 0x89c2756a, 0x798ef478, 0x3e58996b, 
+     0x71b927dd, 0x4fe1beb6, 0xad88f017, 0xac20c966, 0x3ace7db4, 
+     0x4adf6318, 0x311ae582, 0x33519760, 0x7f536245, 0x7764b1e0, 
+     0xae6bbb84, 0xa081fe1c, 0x2b08f994, 0x68487058, 0xfd458f19, 
+     0x6cde9487, 0xf87b52b7, 0xd373ab23, 0x024b72e2, 0x8f1fe357, 
+     0xab55662a, 0x28ebb207, 0xc2b52f03, 0x7bc5869a, 0x0837d3a5, 
+     0x872830f2, 0xa5bf23b2, 0x6a0302ba, 0x8216ed5c, 0x1ccf8a2b, 
+     0xb479a792, 0xf207f3f0, 0xe2694ea1, 0xf4da65cd, 0xbe0506d5, 
+     0x6234d11f, 0xfea6c48a, 0x532e349d, 0x55f3a2a0, 0xe18a0532, 
+     0xebf6a475, 0xec830b39, 0xef6040aa, 0x9f715e06, 0x106ebd51, 
+     0x8a213ef9, 0x06dd963d, 0x053eddae, 0xbde64d46, 0x8d5491b5, 
+     0x5dc47105, 0xd406046f, 0x155060ff, 0xfb981924, 0xe9bdd697, 
+     0x434089cc, 0x9ed96777, 0x42e8b0bd, 0x8b890788, 0x5b19e738, 
+     0xeec879db, 0x0a7ca147, 0x0f427ce9, 0x1e84f8c9, 0x00000000, 
+     0x86800983, 0xed2b3248, 0x70111eac, 0x725a6c4e, 0xff0efdfb, 
+     0x38850f56, 0xd5ae3d1e, 0x392d3627, 0xd90f0a64, 0xa65c6821, 
+     0x545b9bd1, 0x2e36243a, 0x670a0cb1, 0xe757930f, 0x96eeb4d2, 
+     0x919b1b9e, 0xc5c0804f, 0x20dc61a2, 0x4b775a69, 0x1a121c16, 
+     0xba93e20a, 0x2aa0c0e5, 0xe0223c43, 0x171b121d, 0x0d090e0b, 
+     0xc78bf2ad, 0xa8b62db9, 0xa91e14c8, 0x19f15785, 0x0775af4c, 
+     0xdd99eebb, 0x607fa3fd, 0x2601f79f, 0xf5725cbc, 0x3b6644c5, 
+     0x7efb5b34, 0x29438b76, 0xc623cbdc, 0xfcedb668, 0xf1e4b863, 
+     0xdc31d7ca, 0x85634210, 0x22971340, 0x11c68420, 0x244a857d, 
+     0x3dbbd2f8, 0x32f9ae11, 0xa129c76d, 0x2f9e1d4b, 0x30b2dcf3, 
+     0x52860dec, 0xe3c177d0, 0x16b32b6c, 0xb970a999, 0x489411fa, 
+     0x64e94722, 0x8cfca8c4, 0x3ff0a01a, 0x2c7d56d8, 0x903322ef, 
+     0x4e4987c7, 0xd138d9c1, 0xa2ca8cfe, 0x0bd49836, 0x81f5a6cf, 
+     0xde7aa528, 0x8eb7da26, 0xbfad3fa4, 0x9d3a2ce4, 0x9278500d, 
+     0xcc5f6a9b, 0x467e5462, 0x138df6c2, 0xb8d890e8, 0xf7392e5e, 
+     0xafc382f5, 0x805d9fbe, 0x93d0697c, 0x2dd56fa9, 0x1225cfb3, 
+     0x99acc83b, 0x7d1810a7, 0x639ce86e, 0xbb3bdb7b, 0x7826cd09, 
+     0x18596ef4, 0xb79aec01, 0x9a4f83a8, 0x6e95e665, 0xe6ffaa7e, 
+     0xcfbc2108, 0xe815efe6, 0x9be7bad9, 0x366f4ace, 0x099fead4, 
+     0x7cb029d6, 0xb2a431af, 0x233f2a31, 0x94a5c630, 0x66a235c0, 
+     0xbc4e7437, 0xca82fca6, 0xd090e0b0, 0xd8a73315, 0x9804f14a, 
+     0xdaec41f7, 0x50cd7f0e, 0xf691172f, 0xd64d768d, 0xb0ef434d, 
+     0x4daacc54, 0x0496e4df, 0xb5d19ee3, 0x886a4c1b, 0x1f2cc1b8, 
+     0x5165467f, 0xea5e9d04, 0x358c015d, 0x7487fa73, 0x410bfb2e, 
+     0x1d67b35a, 0xd2db9252, 0x5610e933, 0x47d66d13, 0x61d79a8c, 
+     0x0ca1377a, 0x14f8598e, 0x3c13eb89, 0x27a9ceee, 0xc961b735, 
+     0xe51ce1ed, 0xb1477a3c, 0xdfd29c59, 0x73f2553f, 0xce141879, 
+     0x37c773bf, 0xcdf753ea, 0xaafd5f5b, 0x6f3ddf14, 0xdb447886, 
+     0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, 0xc31d1672, 
+     0x25e2bc0c, 0x493c288b, 0x950dff41, 0x01a83971, 0xb30c08de, 
+     0xe4b4d89c, 0xc1566490, 0x84cb7b61, 0xb632d570, 0x5c6c4874, 
+     0x57b8d042};
+
+    private static final int[] Tinv2 =
+    {
+     0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, 0xab3bcb6b, 
+     0x9d1ff145, 0xfaacab58, 0xe34b9303, 0x302055fa, 0x76adf66d, 
+     0xcc889176, 0x02f5254c, 0xe54ffcd7, 0x2ac5d7cb, 0x35268044, 
+     0x62b58fa3, 0xb1de495a, 0xba25671b, 0xea45980e, 0xfe5de1c0, 
+     0x2fc30275, 0x4c8112f0, 0x468da397, 0xd36bc6f9, 0x8f03e75f, 
+     0x9215959c, 0x6dbfeb7a, 0x5295da59, 0xbed42d83, 0x7458d321, 
+     0xe0492969, 0xc98e44c8, 0xc2756a89, 0x8ef47879, 0x58996b3e, 
+     0xb927dd71, 0xe1beb64f, 0x88f017ad, 0x20c966ac, 0xce7db43a, 
+     0xdf63184a, 0x1ae58231, 0x51976033, 0x5362457f, 0x64b1e077, 
+     0x6bbb84ae, 0x81fe1ca0, 0x08f9942b, 0x48705868, 0x458f19fd, 
+     0xde94876c, 0x7b52b7f8, 0x73ab23d3, 0x4b72e202, 0x1fe3578f, 
+     0x55662aab, 0xebb20728, 0xb52f03c2, 0xc5869a7b, 0x37d3a508, 
+     0x2830f287, 0xbf23b2a5, 0x0302ba6a, 0x16ed5c82, 0xcf8a2b1c, 
+     0x79a792b4, 0x07f3f0f2, 0x694ea1e2, 0xda65cdf4, 0x0506d5be, 
+     0x34d11f62, 0xa6c48afe, 0x2e349d53, 0xf3a2a055, 0x8a0532e1, 
+     0xf6a475eb, 0x830b39ec, 0x6040aaef, 0x715e069f, 0x6ebd5110, 
+     0x213ef98a, 0xdd963d06, 0x3eddae05, 0xe64d46bd, 0x5491b58d, 
+     0xc471055d, 0x06046fd4, 0x5060ff15, 0x981924fb, 0xbdd697e9, 
+     0x4089cc43, 0xd967779e, 0xe8b0bd42, 0x8907888b, 0x19e7385b, 
+     0xc879dbee, 0x7ca1470a, 0x427ce90f, 0x84f8c91e, 0x00000000, 
+     0x80098386, 0x2b3248ed, 0x111eac70, 0x5a6c4e72, 0x0efdfbff, 
+     0x850f5638, 0xae3d1ed5, 0x2d362739, 0x0f0a64d9, 0x5c6821a6, 
+     0x5b9bd154, 0x36243a2e, 0x0a0cb167, 0x57930fe7, 0xeeb4d296, 
+     0x9b1b9e91, 0xc0804fc5, 0xdc61a220, 0x775a694b, 0x121c161a, 
+     0x93e20aba, 0xa0c0e52a, 0x223c43e0, 0x1b121d17, 0x090e0b0d, 
+     0x8bf2adc7, 0xb62db9a8, 0x1e14c8a9, 0xf1578519, 0x75af4c07, 
+     0x99eebbdd, 0x7fa3fd60, 0x01f79f26, 0x725cbcf5, 0x6644c53b, 
+     0xfb5b347e, 0x438b7629, 0x23cbdcc6, 0xedb668fc, 0xe4b863f1, 
+     0x31d7cadc, 0x63421085, 0x97134022, 0xc6842011, 0x4a857d24, 
+     0xbbd2f83d, 0xf9ae1132, 0x29c76da1, 0x9e1d4b2f, 0xb2dcf330, 
+     0x860dec52, 0xc177d0e3, 0xb32b6c16, 0x70a999b9, 0x9411fa48, 
+     0xe9472264, 0xfca8c48c, 0xf0a01a3f, 0x7d56d82c, 0x3322ef90, 
+     0x4987c74e, 0x38d9c1d1, 0xca8cfea2, 0xd498360b, 0xf5a6cf81, 
+     0x7aa528de, 0xb7da268e, 0xad3fa4bf, 0x3a2ce49d, 0x78500d92, 
+     0x5f6a9bcc, 0x7e546246, 0x8df6c213, 0xd890e8b8, 0x392e5ef7, 
+     0xc382f5af, 0x5d9fbe80, 0xd0697c93, 0xd56fa92d, 0x25cfb312, 
+     0xacc83b99, 0x1810a77d, 0x9ce86e63, 0x3bdb7bbb, 0x26cd0978, 
+     0x596ef418, 0x9aec01b7, 0x4f83a89a, 0x95e6656e, 0xffaa7ee6, 
+     0xbc2108cf, 0x15efe6e8, 0xe7bad99b, 0x6f4ace36, 0x9fead409, 
+     0xb029d67c, 0xa431afb2, 0x3f2a3123, 0xa5c63094, 0xa235c066, 
+     0x4e7437bc, 0x82fca6ca, 0x90e0b0d0, 0xa73315d8, 0x04f14a98, 
+     0xec41f7da, 0xcd7f0e50, 0x91172ff6, 0x4d768dd6, 0xef434db0, 
+     0xaacc544d, 0x96e4df04, 0xd19ee3b5, 0x6a4c1b88, 0x2cc1b81f, 
+     0x65467f51, 0x5e9d04ea, 0x8c015d35, 0x87fa7374, 0x0bfb2e41, 
+     0x67b35a1d, 0xdb9252d2, 0x10e93356, 0xd66d1347, 0xd79a8c61, 
+     0xa1377a0c, 0xf8598e14, 0x13eb893c, 0xa9ceee27, 0x61b735c9, 
+     0x1ce1ede5, 0x477a3cb1, 0xd29c59df, 0xf2553f73, 0x141879ce, 
+     0xc773bf37, 0xf753eacd, 0xfd5f5baa, 0x3ddf146f, 0x447886db, 
+     0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, 0x1d1672c3, 
+     0xe2bc0c25, 0x3c288b49, 0x0dff4195, 0xa8397101, 0x0c08deb3, 
+     0xb4d89ce4, 0x566490c1, 0xcb7b6184, 0x32d570b6, 0x6c48745c, 
+     0xb8d04257};
+
+    private static final int[] Tinv3 =
+    {
+     0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, 0x3bcb6bab, 
+     0x1ff1459d, 0xacab58fa, 0x4b9303e3, 0x2055fa30, 0xadf66d76, 
+     0x889176cc, 0xf5254c02, 0x4ffcd7e5, 0xc5d7cb2a, 0x26804435, 
+     0xb58fa362, 0xde495ab1, 0x25671bba, 0x45980eea, 0x5de1c0fe, 
+     0xc302752f, 0x8112f04c, 0x8da39746, 0x6bc6f9d3, 0x03e75f8f, 
+     0x15959c92, 0xbfeb7a6d, 0x95da5952, 0xd42d83be, 0x58d32174, 
+     0x492969e0, 0x8e44c8c9, 0x756a89c2, 0xf478798e, 0x996b3e58, 
+     0x27dd71b9, 0xbeb64fe1, 0xf017ad88, 0xc966ac20, 0x7db43ace, 
+     0x63184adf, 0xe582311a, 0x97603351, 0x62457f53, 0xb1e07764, 
+     0xbb84ae6b, 0xfe1ca081, 0xf9942b08, 0x70586848, 0x8f19fd45, 
+     0x94876cde, 0x52b7f87b, 0xab23d373, 0x72e2024b, 0xe3578f1f, 
+     0x662aab55, 0xb20728eb, 0x2f03c2b5, 0x869a7bc5, 0xd3a50837, 
+     0x30f28728, 0x23b2a5bf, 0x02ba6a03, 0xed5c8216, 0x8a2b1ccf, 
+     0xa792b479, 0xf3f0f207, 0x4ea1e269, 0x65cdf4da, 0x06d5be05, 
+     0xd11f6234, 0xc48afea6, 0x349d532e, 0xa2a055f3, 0x0532e18a, 
+     0xa475ebf6, 0x0b39ec83, 0x40aaef60, 0x5e069f71, 0xbd51106e, 
+     0x3ef98a21, 0x963d06dd, 0xddae053e, 0x4d46bde6, 0x91b58d54, 
+     0x71055dc4, 0x046fd406, 0x60ff1550, 0x1924fb98, 0xd697e9bd, 
+     0x89cc4340, 0x67779ed9, 0xb0bd42e8, 0x07888b89, 0xe7385b19, 
+     0x79dbeec8, 0xa1470a7c, 0x7ce90f42, 0xf8c91e84, 0x00000000, 
+     0x09838680, 0x3248ed2b, 0x1eac7011, 0x6c4e725a, 0xfdfbff0e, 
+     0x0f563885, 0x3d1ed5ae, 0x3627392d, 0x0a64d90f, 0x6821a65c, 
+     0x9bd1545b, 0x243a2e36, 0x0cb1670a, 0x930fe757, 0xb4d296ee, 
+     0x1b9e919b, 0x804fc5c0, 0x61a220dc, 0x5a694b77, 0x1c161a12, 
+     0xe20aba93, 0xc0e52aa0, 0x3c43e022, 0x121d171b, 0x0e0b0d09, 
+     0xf2adc78b, 0x2db9a8b6, 0x14c8a91e, 0x578519f1, 0xaf4c0775, 
+     0xeebbdd99, 0xa3fd607f, 0xf79f2601, 0x5cbcf572, 0x44c53b66, 
+     0x5b347efb, 0x8b762943, 0xcbdcc623, 0xb668fced, 0xb863f1e4, 
+     0xd7cadc31, 0x42108563, 0x13402297, 0x842011c6, 0x857d244a, 
+     0xd2f83dbb, 0xae1132f9, 0xc76da129, 0x1d4b2f9e, 0xdcf330b2, 
+     0x0dec5286, 0x77d0e3c1, 0x2b6c16b3, 0xa999b970, 0x11fa4894, 
+     0x472264e9, 0xa8c48cfc, 0xa01a3ff0, 0x56d82c7d, 0x22ef9033, 
+     0x87c74e49, 0xd9c1d138, 0x8cfea2ca, 0x98360bd4, 0xa6cf81f5, 
+     0xa528de7a, 0xda268eb7, 0x3fa4bfad, 0x2ce49d3a, 0x500d9278, 
+     0x6a9bcc5f, 0x5462467e, 0xf6c2138d, 0x90e8b8d8, 0x2e5ef739, 
+     0x82f5afc3, 0x9fbe805d, 0x697c93d0, 0x6fa92dd5, 0xcfb31225, 
+     0xc83b99ac, 0x10a77d18, 0xe86e639c, 0xdb7bbb3b, 0xcd097826, 
+     0x6ef41859, 0xec01b79a, 0x83a89a4f, 0xe6656e95, 0xaa7ee6ff, 
+     0x2108cfbc, 0xefe6e815, 0xbad99be7, 0x4ace366f, 0xead4099f, 
+     0x29d67cb0, 0x31afb2a4, 0x2a31233f, 0xc63094a5, 0x35c066a2, 
+     0x7437bc4e, 0xfca6ca82, 0xe0b0d090, 0x3315d8a7, 0xf14a9804, 
+     0x41f7daec, 0x7f0e50cd, 0x172ff691, 0x768dd64d, 0x434db0ef, 
+     0xcc544daa, 0xe4df0496, 0x9ee3b5d1, 0x4c1b886a, 0xc1b81f2c, 
+     0x467f5165, 0x9d04ea5e, 0x015d358c, 0xfa737487, 0xfb2e410b, 
+     0xb35a1d67, 0x9252d2db, 0xe9335610, 0x6d1347d6, 0x9a8c61d7, 
+     0x377a0ca1, 0x598e14f8, 0xeb893c13, 0xceee27a9, 0xb735c961, 
+     0xe1ede51c, 0x7a3cb147, 0x9c59dfd2, 0x553f73f2, 0x1879ce14, 
+     0x73bf37c7, 0x53eacdf7, 0x5f5baafd, 0xdf146f3d, 0x7886db44, 
+     0xca81f3af, 0xb93ec468, 0x382c3424, 0xc25f40a3, 0x1672c31d, 
+     0xbc0c25e2, 0x288b493c, 0xff41950d, 0x397101a8, 0x08deb30c, 
+     0xd89ce4b4, 0x6490c156, 0x7b6184cb, 0xd570b632, 0x48745c6c, 
+     0xd04257b8};
+
+    private int shift(
+        int     r,
+        int     shift)
+    {
+        return (r >>> shift) | (r << -shift);
+    }
+
+    /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
+
+    private static final int m1 = 0x80808080;
+    private static final int m2 = 0x7f7f7f7f;
+    private static final int m3 = 0x0000001b;
+
+    private int FFmulX(int x)
+    {
+        return (((x & m2) << 1) ^ (((x & m1) >>> 7) * m3));
+    }
+
+    /* 
+       The following defines provide alternative definitions of FFmulX that might
+       give improved performance if a fast 32-bit multiply is not available.
+       
+       private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); } 
+       private static final int  m4 = 0x1b1b1b1b;
+       private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); } 
+
+    */
+
+    private int inv_mcol(int x)
+    {
+        int f2 = FFmulX(x);
+        int f4 = FFmulX(f2);
+        int f8 = FFmulX(f4);
+        int f9 = x ^ f8;
+        
+        return f2 ^ f4 ^ f8 ^ shift(f2 ^ f9, 8) ^ shift(f4 ^ f9, 16) ^ shift(f9, 24);
+    }
+
+
+    private int subWord(int x)
+    {
+        return (S[x&255]&255 | ((S[(x>>8)&255]&255)<<8) | ((S[(x>>16)&255]&255)<<16) | S[(x>>24)&255]<<24);
+    }
+
+    /**
+     * Calculate the necessary round keys
+     * The number of calculations depends on key size and block size
+     * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
+     * This code is written assuming those are the only possible values
+     */
+    private int[][] generateWorkingKey(
+                                    byte[] key,
+                                    boolean forEncryption)
+    {
+        int         KC = key.length / 4;  // key length in words
+        int         t;
+        
+        if (((KC != 4) && (KC != 6) && (KC != 8)) || ((KC * 4) != key.length))
+        {
+            throw new IllegalArgumentException("Key length not 128/192/256 bits.");
+        }
+
+        ROUNDS = KC + 6;  // This is not always true for the generalized Rijndael that allows larger block sizes
+        int[][] W = new int[ROUNDS+1][4];   // 4 words in a block
+        
+        //
+        // copy the key into the round key array
+        //
+        
+        t = 0;
+        int i = 0;
+        while (i < key.length)
+        {
+            W[t >> 2][t & 3] = (key[i]&0xff) | ((key[i+1]&0xff) << 8) | ((key[i+2]&0xff) << 16) | (key[i+3] << 24);
+            i+=4;
+            t++;
+        }
+        
+        //
+        // while not enough round key material calculated
+        // calculate new values
+        //
+        int k = (ROUNDS + 1) << 2;
+        for (i = KC; (i < k); i++)
+        {
+            int temp = W[(i - 1) >> 2][(i - 1) & 3];
+            if ((i % KC) == 0)
+            {
+                temp = subWord(shift(temp, 8)) ^ rcon[(i / KC) - 1];
+            }
+            else if ((KC > 6) && ((i % KC) == 4))
+            {
+                temp = subWord(temp);
+            }
+
+            W[i >> 2][i & 3] = W[(i - KC) >> 2][(i - KC) & 3] ^ temp;
+        }
+
+        if (!forEncryption)
+        {
+            for (int j = 1; j < ROUNDS; j++)
+            {
+                for (i = 0; i < 4; i++)
+                {
+                    W[j][i] = inv_mcol(W[j][i]);
+                }
+            }
+        }
+
+        return W;
+    }
+
+    private int         ROUNDS;
+    private int[][]     WorkingKey = null;
+    private int         C0, C1, C2, C3;
+    private boolean     forEncryption;
+
+    private static final int BLOCK_SIZE = 16;
+
+    /**
+     * default constructor - 128 bit block size.
+     */
+    public AESFastEngine()
+    {
+    }
+
+    /**
+     * initialise an AES cipher.
+     *
+     * @param forEncryption whether or not we are for encryption.
+     * @param params the parameters required to set up the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean           forEncryption,
+        CipherParameters  params)
+    {
+        if (params instanceof KeyParameter)
+        {
+            WorkingKey = generateWorkingKey(((KeyParameter)params).getKey(), forEncryption);
+            this.forEncryption = forEncryption;
+            return;
+        }
+
+        throw new IllegalArgumentException("invalid parameter passed to AES init - " + params.getClass().getName());
+    }
+
+    public String getAlgorithmName()
+    {
+        return "AES";
+    }
+
+    public int getBlockSize()
+    {
+        return BLOCK_SIZE;
+    }
+
+    public int processBlock(
+        byte[] in,
+        int inOff,
+        byte[] out,
+        int outOff)
+    {
+        if (WorkingKey == null)
+        {
+            throw new IllegalStateException("AES engine not initialised");
+        }
+
+        if ((inOff + (32 / 2)) > in.length)
+        {
+            throw new DataLengthException("input buffer too short");
+        }
+
+        if ((outOff + (32 / 2)) > out.length)
+        {
+            throw new DataLengthException("output buffer too short");
+        }
+
+        if (forEncryption)
+        {
+            unpackBlock(in, inOff);
+            encryptBlock(WorkingKey);
+            packBlock(out, outOff);
+        }
+        else
+        {
+            unpackBlock(in, inOff);
+            decryptBlock(WorkingKey);
+            packBlock(out, outOff);
+        }
+
+        return BLOCK_SIZE;
+    }
+
+    public void reset()
+    {
+    }
+
+    private final void unpackBlock(
+        byte[]      bytes,
+        int         off)
+    {
+        int     index = off;
+
+        C0 = (bytes[index++] & 0xff);
+        C0 |= (bytes[index++] & 0xff) << 8;
+        C0 |= (bytes[index++] & 0xff) << 16;
+        C0 |= bytes[index++] << 24;
+
+        C1 = (bytes[index++] & 0xff);
+        C1 |= (bytes[index++] & 0xff) << 8;
+        C1 |= (bytes[index++] & 0xff) << 16;
+        C1 |= bytes[index++] << 24;
+
+        C2 = (bytes[index++] & 0xff);
+        C2 |= (bytes[index++] & 0xff) << 8;
+        C2 |= (bytes[index++] & 0xff) << 16;
+        C2 |= bytes[index++] << 24;
+
+        C3 = (bytes[index++] & 0xff);
+        C3 |= (bytes[index++] & 0xff) << 8;
+        C3 |= (bytes[index++] & 0xff) << 16;
+        C3 |= bytes[index++] << 24;
+    }
+
+    private final void packBlock(
+        byte[]      bytes,
+        int         off)
+    {
+        int     index = off;
+
+        bytes[index++] = (byte)C0;
+        bytes[index++] = (byte)(C0 >> 8);
+        bytes[index++] = (byte)(C0 >> 16);
+        bytes[index++] = (byte)(C0 >> 24);
+
+        bytes[index++] = (byte)C1;
+        bytes[index++] = (byte)(C1 >> 8);
+        bytes[index++] = (byte)(C1 >> 16);
+        bytes[index++] = (byte)(C1 >> 24);
+
+        bytes[index++] = (byte)C2;
+        bytes[index++] = (byte)(C2 >> 8);
+        bytes[index++] = (byte)(C2 >> 16);
+        bytes[index++] = (byte)(C2 >> 24);
+
+        bytes[index++] = (byte)C3;
+        bytes[index++] = (byte)(C3 >> 8);
+        bytes[index++] = (byte)(C3 >> 16);
+        bytes[index++] = (byte)(C3 >> 24);
+    }
+
+    private final void encryptBlock(int[][] KW)
+    {
+        int r, r0, r1, r2, r3;
+        
+        C0 ^= KW[0][0];
+        C1 ^= KW[0][1];
+        C2 ^= KW[0][2];
+        C3 ^= KW[0][3];
+
+        r = 1;
+        while (r < ROUNDS - 1)
+        {
+            r0 = T0[C0&255] ^ T1[(C1>>8)&255] ^ T2[(C2>>16)&255] ^ T3[(C3>>24)&255] ^ KW[r][0];
+            r1 = T0[C1&255] ^ T1[(C2>>8)&255] ^ T2[(C3>>16)&255] ^ T3[(C0>>24)&255] ^ KW[r][1];
+            r2 = T0[C2&255] ^ T1[(C3>>8)&255] ^ T2[(C0>>16)&255] ^ T3[(C1>>24)&255] ^ KW[r][2];
+            r3 = T0[C3&255] ^ T1[(C0>>8)&255] ^ T2[(C1>>16)&255] ^ T3[(C2>>24)&255] ^ KW[r++][3];
+            C0 = T0[r0&255] ^ T1[(r1>>8)&255] ^ T2[(r2>>16)&255] ^ T3[(r3>>24)&255] ^ KW[r][0];
+            C1 = T0[r1&255] ^ T1[(r2>>8)&255] ^ T2[(r3>>16)&255] ^ T3[(r0>>24)&255] ^ KW[r][1];
+            C2 = T0[r2&255] ^ T1[(r3>>8)&255] ^ T2[(r0>>16)&255] ^ T3[(r1>>24)&255] ^ KW[r][2];
+            C3 = T0[r3&255] ^ T1[(r0>>8)&255] ^ T2[(r1>>16)&255] ^ T3[(r2>>24)&255] ^ KW[r++][3];
+        }
+
+        r0 = T0[C0&255] ^ T1[(C1>>8)&255] ^ T2[(C2>>16)&255] ^ T3[(C3>>24)&255] ^ KW[r][0];
+        r1 = T0[C1&255] ^ T1[(C2>>8)&255] ^ T2[(C3>>16)&255] ^ T3[(C0>>24)&255] ^ KW[r][1];
+        r2 = T0[C2&255] ^ T1[(C3>>8)&255] ^ T2[(C0>>16)&255] ^ T3[(C1>>24)&255] ^ KW[r][2];
+        r3 = T0[C3&255] ^ T1[(C0>>8)&255] ^ T2[(C1>>16)&255] ^ T3[(C2>>24)&255] ^ KW[r++][3];
+        
+        // the final round's table is a simple function of S so we don't use a whole other four tables for it
+
+        C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r][0];
+        C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r][1];
+        C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r][2];
+        C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r][3];
+
+    }
+
+    private final void decryptBlock(int[][] KW)
+    {
+        int r0, r1, r2, r3;
+
+        C0 ^= KW[ROUNDS][0];
+        C1 ^= KW[ROUNDS][1];
+        C2 ^= KW[ROUNDS][2];
+        C3 ^= KW[ROUNDS][3];
+
+        int r = ROUNDS-1; 
+        
+        while (r>1) 
+        {
+            r0 = Tinv0[C0&255] ^ Tinv1[(C3>>8)&255] ^ Tinv2[(C2>>16)&255] ^ Tinv3[(C1>>24)&255] ^ KW[r][0];
+            r1 = Tinv0[C1&255] ^ Tinv1[(C0>>8)&255] ^ Tinv2[(C3>>16)&255] ^ Tinv3[(C2>>24)&255] ^ KW[r][1];
+            r2 = Tinv0[C2&255] ^ Tinv1[(C1>>8)&255] ^ Tinv2[(C0>>16)&255] ^ Tinv3[(C3>>24)&255] ^ KW[r][2];
+            r3 = Tinv0[C3&255] ^ Tinv1[(C2>>8)&255] ^ Tinv2[(C1>>16)&255] ^ Tinv3[(C0>>24)&255] ^ KW[r--][3];
+            C0 = Tinv0[r0&255] ^ Tinv1[(r3>>8)&255] ^ Tinv2[(r2>>16)&255] ^ Tinv3[(r1>>24)&255] ^ KW[r][0];
+            C1 = Tinv0[r1&255] ^ Tinv1[(r0>>8)&255] ^ Tinv2[(r3>>16)&255] ^ Tinv3[(r2>>24)&255] ^ KW[r][1];
+            C2 = Tinv0[r2&255] ^ Tinv1[(r1>>8)&255] ^ Tinv2[(r0>>16)&255] ^ Tinv3[(r3>>24)&255] ^ KW[r][2];
+            C3 = Tinv0[r3&255] ^ Tinv1[(r2>>8)&255] ^ Tinv2[(r1>>16)&255] ^ Tinv3[(r0>>24)&255] ^ KW[r--][3];
+        }
+
+        r0 = Tinv0[C0&255] ^ Tinv1[(C3>>8)&255] ^ Tinv2[(C2>>16)&255] ^ Tinv3[(C1>>24)&255] ^ KW[r][0];
+        r1 = Tinv0[C1&255] ^ Tinv1[(C0>>8)&255] ^ Tinv2[(C3>>16)&255] ^ Tinv3[(C2>>24)&255] ^ KW[r][1];
+        r2 = Tinv0[C2&255] ^ Tinv1[(C1>>8)&255] ^ Tinv2[(C0>>16)&255] ^ Tinv3[(C3>>24)&255] ^ KW[r][2];
+        r3 = Tinv0[C3&255] ^ Tinv1[(C2>>8)&255] ^ Tinv2[(C1>>16)&255] ^ Tinv3[(C0>>24)&255] ^ KW[r--][3];
+        
+        // the final round's table is a simple function of Si so we don't use a whole other four tables for it
+
+        C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0][0];
+        C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0][1];
+        C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0][2];
+        C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0][3];
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/engines/AESLightEngine.java b/libcore/security/src/main/java/org/bouncycastle/crypto/engines/AESLightEngine.java
new file mode 100644
index 0000000..b0730e3
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/engines/AESLightEngine.java
@@ -0,0 +1,440 @@
+package org.bouncycastle.crypto.engines;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.KeyParameter;
+
+/**
+ * an implementation of the AES (Rijndael), from FIPS-197.
+ * <p>
+ * For further details see: <a href="http://csrc.nist.gov/encryption/aes/">http://csrc.nist.gov/encryption/aes/</a>.
+ *
+ * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
+ * <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/">http://fp.gladman.plus.com/cryptography_technology/rijndael/</a>
+ *
+ * There are three levels of tradeoff of speed vs memory
+ * Because java has no preprocessor, they are written as three separate classes from which to choose
+ *
+ * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption
+ * and 4 for decryption.
+ *
+ * The middle performance version uses only one 256 word table for each, for a total of 2Kbytes,
+ * adding 12 rotate operations per round to compute the values contained in the other tables from
+ * the contents of the first
+ *
+ * The slowest version uses no static tables at all and computes the values
+ * in each round.
+ * <p>
+ * This file contains the slowest performance version with no static tables
+ * for round precomputation, but it has the smallest foot print.
+ *
+ */
+public class AESLightEngine
+    implements BlockCipher
+{
+    // The S box
+    private static final byte[] S = {
+        (byte)99, (byte)124, (byte)119, (byte)123, (byte)242, (byte)107, (byte)111, (byte)197,
+        (byte)48,   (byte)1, (byte)103,  (byte)43, (byte)254, (byte)215, (byte)171, (byte)118,
+        (byte)202, (byte)130, (byte)201, (byte)125, (byte)250,  (byte)89,  (byte)71, (byte)240,
+        (byte)173, (byte)212, (byte)162, (byte)175, (byte)156, (byte)164, (byte)114, (byte)192,
+        (byte)183, (byte)253, (byte)147,  (byte)38,  (byte)54,  (byte)63, (byte)247, (byte)204,
+        (byte)52, (byte)165, (byte)229, (byte)241, (byte)113, (byte)216,  (byte)49,  (byte)21,
+        (byte)4, (byte)199,  (byte)35, (byte)195,  (byte)24, (byte)150,   (byte)5, (byte)154,
+        (byte)7,  (byte)18, (byte)128, (byte)226, (byte)235,  (byte)39, (byte)178, (byte)117,
+        (byte)9, (byte)131,  (byte)44,  (byte)26,  (byte)27, (byte)110,  (byte)90, (byte)160,
+        (byte)82,  (byte)59, (byte)214, (byte)179,  (byte)41, (byte)227,  (byte)47, (byte)132,
+        (byte)83, (byte)209,   (byte)0, (byte)237,  (byte)32, (byte)252, (byte)177,  (byte)91,
+        (byte)106, (byte)203, (byte)190,  (byte)57,  (byte)74,  (byte)76,  (byte)88, (byte)207,
+        (byte)208, (byte)239, (byte)170, (byte)251,  (byte)67,  (byte)77,  (byte)51, (byte)133,
+        (byte)69, (byte)249,   (byte)2, (byte)127,  (byte)80,  (byte)60, (byte)159, (byte)168,
+        (byte)81, (byte)163,  (byte)64, (byte)143, (byte)146, (byte)157,  (byte)56, (byte)245,
+        (byte)188, (byte)182, (byte)218,  (byte)33,  (byte)16, (byte)255, (byte)243, (byte)210,
+        (byte)205,  (byte)12,  (byte)19, (byte)236,  (byte)95, (byte)151,  (byte)68,  (byte)23,
+        (byte)196, (byte)167, (byte)126,  (byte)61, (byte)100,  (byte)93,  (byte)25, (byte)115,
+        (byte)96, (byte)129,  (byte)79, (byte)220,  (byte)34,  (byte)42, (byte)144, (byte)136,
+        (byte)70, (byte)238, (byte)184,  (byte)20, (byte)222,  (byte)94,  (byte)11, (byte)219,
+        (byte)224,  (byte)50,  (byte)58,  (byte)10,  (byte)73,   (byte)6,  (byte)36,  (byte)92,
+        (byte)194, (byte)211, (byte)172,  (byte)98, (byte)145, (byte)149, (byte)228, (byte)121,
+        (byte)231, (byte)200,  (byte)55, (byte)109, (byte)141, (byte)213,  (byte)78, (byte)169,
+        (byte)108,  (byte)86, (byte)244, (byte)234, (byte)101, (byte)122, (byte)174,   (byte)8,
+        (byte)186, (byte)120,  (byte)37,  (byte)46,  (byte)28, (byte)166, (byte)180, (byte)198,
+        (byte)232, (byte)221, (byte)116,  (byte)31,  (byte)75, (byte)189, (byte)139, (byte)138,
+        (byte)112,  (byte)62, (byte)181, (byte)102,  (byte)72,   (byte)3, (byte)246,  (byte)14,
+        (byte)97,  (byte)53,  (byte)87, (byte)185, (byte)134, (byte)193,  (byte)29, (byte)158,
+        (byte)225, (byte)248, (byte)152,  (byte)17, (byte)105, (byte)217, (byte)142, (byte)148,
+        (byte)155,  (byte)30, (byte)135, (byte)233, (byte)206,  (byte)85,  (byte)40, (byte)223,
+        (byte)140, (byte)161, (byte)137,  (byte)13, (byte)191, (byte)230,  (byte)66, (byte)104,
+        (byte)65, (byte)153,  (byte)45,  (byte)15, (byte)176,  (byte)84, (byte)187,  (byte)22,
+    };
+
+    // The inverse S-box
+    private static final byte[] Si = {
+        (byte)82,   (byte)9, (byte)106, (byte)213,  (byte)48,  (byte)54, (byte)165,  (byte)56,
+        (byte)191,  (byte)64, (byte)163, (byte)158, (byte)129, (byte)243, (byte)215, (byte)251,
+        (byte)124, (byte)227,  (byte)57, (byte)130, (byte)155,  (byte)47, (byte)255, (byte)135,
+        (byte)52, (byte)142,  (byte)67,  (byte)68, (byte)196, (byte)222, (byte)233, (byte)203,
+        (byte)84, (byte)123, (byte)148,  (byte)50, (byte)166, (byte)194,  (byte)35,  (byte)61,
+        (byte)238,  (byte)76, (byte)149,  (byte)11,  (byte)66, (byte)250, (byte)195,  (byte)78,
+        (byte)8,  (byte)46, (byte)161, (byte)102,  (byte)40, (byte)217,  (byte)36, (byte)178,
+        (byte)118,  (byte)91, (byte)162,  (byte)73, (byte)109, (byte)139, (byte)209,  (byte)37,
+        (byte)114, (byte)248, (byte)246, (byte)100, (byte)134, (byte)104, (byte)152,  (byte)22,
+        (byte)212, (byte)164,  (byte)92, (byte)204,  (byte)93, (byte)101, (byte)182, (byte)146,
+        (byte)108, (byte)112,  (byte)72,  (byte)80, (byte)253, (byte)237, (byte)185, (byte)218,
+        (byte)94,  (byte)21,  (byte)70,  (byte)87, (byte)167, (byte)141, (byte)157, (byte)132,
+        (byte)144, (byte)216, (byte)171,   (byte)0, (byte)140, (byte)188, (byte)211,  (byte)10,
+        (byte)247, (byte)228,  (byte)88,   (byte)5, (byte)184, (byte)179,  (byte)69,   (byte)6,
+        (byte)208,  (byte)44,  (byte)30, (byte)143, (byte)202,  (byte)63,  (byte)15,   (byte)2,
+        (byte)193, (byte)175, (byte)189,   (byte)3,   (byte)1,  (byte)19, (byte)138, (byte)107,
+        (byte)58, (byte)145,  (byte)17,  (byte)65,  (byte)79, (byte)103, (byte)220, (byte)234,
+        (byte)151, (byte)242, (byte)207, (byte)206, (byte)240, (byte)180, (byte)230, (byte)115,
+        (byte)150, (byte)172, (byte)116,  (byte)34, (byte)231, (byte)173,  (byte)53, (byte)133,
+        (byte)226, (byte)249,  (byte)55, (byte)232,  (byte)28, (byte)117, (byte)223, (byte)110,
+        (byte)71, (byte)241,  (byte)26, (byte)113,  (byte)29,  (byte)41, (byte)197, (byte)137,
+        (byte)111, (byte)183,  (byte)98,  (byte)14, (byte)170,  (byte)24, (byte)190,  (byte)27,
+        (byte)252,  (byte)86,  (byte)62,  (byte)75, (byte)198, (byte)210, (byte)121,  (byte)32,
+        (byte)154, (byte)219, (byte)192, (byte)254, (byte)120, (byte)205,  (byte)90, (byte)244,
+        (byte)31, (byte)221, (byte)168,  (byte)51, (byte)136,   (byte)7, (byte)199,  (byte)49,
+        (byte)177,  (byte)18,  (byte)16,  (byte)89,  (byte)39, (byte)128, (byte)236,  (byte)95,
+        (byte)96,  (byte)81, (byte)127, (byte)169,  (byte)25, (byte)181,  (byte)74,  (byte)13,
+        (byte)45, (byte)229, (byte)122, (byte)159, (byte)147, (byte)201, (byte)156, (byte)239,
+        (byte)160, (byte)224,  (byte)59,  (byte)77, (byte)174,  (byte)42, (byte)245, (byte)176,
+        (byte)200, (byte)235, (byte)187,  (byte)60, (byte)131,  (byte)83, (byte)153,  (byte)97,
+        (byte)23,  (byte)43,   (byte)4, (byte)126, (byte)186, (byte)119, (byte)214,  (byte)38,
+        (byte)225, (byte)105,  (byte)20,  (byte)99,  (byte)85,  (byte)33,  (byte)12, (byte)125,
+        };
+
+    // vector used in calculating key schedule (powers of x in GF(256))
+    private static final int[] rcon = {
+         0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
+         0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 };
+
+    private int shift(
+        int     r,
+        int     shift)
+    {
+        return (r >>> shift) | (r << -shift);
+    }
+
+    /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
+
+    private static final int m1 = 0x80808080;
+    private static final int m2 = 0x7f7f7f7f;
+    private static final int m3 = 0x0000001b;
+
+    private int FFmulX(int x)
+    {
+        return (((x & m2) << 1) ^ (((x & m1) >>> 7) * m3));
+    }
+
+    /* 
+       The following defines provide alternative definitions of FFmulX that might
+       give improved performance if a fast 32-bit multiply is not available.
+       
+       private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); } 
+       private static final int  m4 = 0x1b1b1b1b;
+       private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); } 
+
+    */
+
+    private int mcol(int x)
+    {
+        int f2 = FFmulX(x);
+        return f2 ^ shift(x ^ f2, 8) ^ shift(x, 16) ^ shift(x, 24);
+    }
+
+    private int inv_mcol(int x)
+    {
+        int f2 = FFmulX(x);
+        int f4 = FFmulX(f2);
+        int f8 = FFmulX(f4);
+        int f9 = x ^ f8;
+        
+        return f2 ^ f4 ^ f8 ^ shift(f2 ^ f9, 8) ^ shift(f4 ^ f9, 16) ^ shift(f9, 24);
+    }
+
+
+    private int subWord(int x)
+    {
+        return (S[x&255]&255 | ((S[(x>>8)&255]&255)<<8) | ((S[(x>>16)&255]&255)<<16) | S[(x>>24)&255]<<24);
+    }
+
+    /**
+     * Calculate the necessary round keys
+     * The number of calculations depends on key size and block size
+     * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
+     * This code is written assuming those are the only possible values
+     */
+    private int[][] generateWorkingKey(
+                                    byte[] key,
+                                    boolean forEncryption)
+    {
+        int         KC = key.length / 4;  // key length in words
+        int         t;
+        
+        if (((KC != 4) && (KC != 6) && (KC != 8)) || ((KC * 4) != key.length))
+        {
+            throw new IllegalArgumentException("Key length not 128/192/256 bits.");
+        }
+
+        ROUNDS = KC + 6;  // This is not always true for the generalized Rijndael that allows larger block sizes
+        int[][] W = new int[ROUNDS+1][4];   // 4 words in a block
+        
+        //
+        // copy the key into the round key array
+        //
+        
+        t = 0;
+        int i = 0;
+        while (i < key.length)
+            {
+                W[t >> 2][t & 3] = (key[i]&0xff) | ((key[i+1]&0xff) << 8) | ((key[i+2]&0xff) << 16) | (key[i+3] << 24);
+                i+=4;
+                t++;
+            }
+        
+        //
+        // while not enough round key material calculated
+        // calculate new values
+        //
+        int k = (ROUNDS + 1) << 2;
+        for (i = KC; (i < k); i++)
+            {
+                int temp = W[(i-1)>>2][(i-1)&3];
+                if ((i % KC) == 0)
+                {
+                    temp = subWord(shift(temp, 8)) ^ rcon[(i / KC)-1];
+                }
+                else if ((KC > 6) && ((i % KC) == 4))
+                {
+                    temp = subWord(temp);
+                }
+                
+                W[i>>2][i&3] = W[(i - KC)>>2][(i-KC)&3] ^ temp;
+            }
+
+        if (!forEncryption)
+        {
+            for (int j = 1; j < ROUNDS; j++)
+            {
+                for (i = 0; i < 4; i++) 
+                {
+                    W[j][i] = inv_mcol(W[j][i]);
+                }
+            }
+        }
+
+        return W;
+    }
+
+    private int         ROUNDS;
+    private int[][]     WorkingKey = null;
+    private int         C0, C1, C2, C3;
+    private boolean     forEncryption;
+
+    private static final int BLOCK_SIZE = 16;
+
+    /**
+     * default constructor - 128 bit block size.
+     */
+    public AESLightEngine()
+    {
+    }
+
+    /**
+     * initialise an AES cipher.
+     *
+     * @param forEncryption whether or not we are for encryption.
+     * @param params the parameters required to set up the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean           forEncryption,
+        CipherParameters  params)
+    {
+        if (params instanceof KeyParameter)
+        {
+            WorkingKey = generateWorkingKey(((KeyParameter)params).getKey(), forEncryption);
+            this.forEncryption = forEncryption;
+            return;
+        }
+
+        throw new IllegalArgumentException("invalid parameter passed to AES init - " + params.getClass().getName());
+    }
+
+    public String getAlgorithmName()
+    {
+        return "AES";
+    }
+
+    public int getBlockSize()
+    {
+        return BLOCK_SIZE;
+    }
+
+    public int processBlock(
+        byte[] in,
+        int inOff,
+        byte[] out,
+        int outOff)
+    {
+        if (WorkingKey == null)
+        {
+            throw new IllegalStateException("AES engine not initialised");
+        }
+
+        if ((inOff + (32 / 2)) > in.length)
+        {
+            throw new DataLengthException("input buffer too short");
+        }
+
+        if ((outOff + (32 / 2)) > out.length)
+        {
+            throw new DataLengthException("output buffer too short");
+        }
+
+        if (forEncryption)
+        {
+            unpackBlock(in, inOff);
+            encryptBlock(WorkingKey);
+            packBlock(out, outOff);
+        }
+        else
+        {
+            unpackBlock(in, inOff);
+            decryptBlock(WorkingKey);
+            packBlock(out, outOff);
+        }
+
+        return BLOCK_SIZE;
+    }
+
+    public void reset()
+    {
+    }
+
+    private final void unpackBlock(
+        byte[]      bytes,
+        int         off)
+    {
+        int     index = off;
+
+        C0 = (bytes[index++] & 0xff);
+        C0 |= (bytes[index++] & 0xff) << 8;
+        C0 |= (bytes[index++] & 0xff) << 16;
+        C0 |= bytes[index++] << 24;
+
+        C1 = (bytes[index++] & 0xff);
+        C1 |= (bytes[index++] & 0xff) << 8;
+        C1 |= (bytes[index++] & 0xff) << 16;
+        C1 |= bytes[index++] << 24;
+
+        C2 = (bytes[index++] & 0xff);
+        C2 |= (bytes[index++] & 0xff) << 8;
+        C2 |= (bytes[index++] & 0xff) << 16;
+        C2 |= bytes[index++] << 24;
+
+        C3 = (bytes[index++] & 0xff);
+        C3 |= (bytes[index++] & 0xff) << 8;
+        C3 |= (bytes[index++] & 0xff) << 16;
+        C3 |= bytes[index++] << 24;
+    }
+
+    private final void packBlock(
+        byte[]      bytes,
+        int         off)
+    {
+        int     index = off;
+
+        bytes[index++] = (byte)C0;
+        bytes[index++] = (byte)(C0 >> 8);
+        bytes[index++] = (byte)(C0 >> 16);
+        bytes[index++] = (byte)(C0 >> 24);
+
+        bytes[index++] = (byte)C1;
+        bytes[index++] = (byte)(C1 >> 8);
+        bytes[index++] = (byte)(C1 >> 16);
+        bytes[index++] = (byte)(C1 >> 24);
+
+        bytes[index++] = (byte)C2;
+        bytes[index++] = (byte)(C2 >> 8);
+        bytes[index++] = (byte)(C2 >> 16);
+        bytes[index++] = (byte)(C2 >> 24);
+
+        bytes[index++] = (byte)C3;
+        bytes[index++] = (byte)(C3 >> 8);
+        bytes[index++] = (byte)(C3 >> 16);
+        bytes[index++] = (byte)(C3 >> 24);
+    }
+
+    private void encryptBlock(int[][] KW)
+    {
+        int r, r0, r1, r2, r3;
+
+        C0 ^= KW[0][0];
+        C1 ^= KW[0][1];
+        C2 ^= KW[0][2];
+        C3 ^= KW[0][3];
+
+        for (r = 1; r < ROUNDS - 1;)
+        {
+            r0 = mcol((S[C0&255]&255) ^ ((S[(C1>>8)&255]&255)<<8) ^ ((S[(C2>>16)&255]&255)<<16) ^ (S[(C3>>24)&255]<<24)) ^ KW[r][0];
+            r1 = mcol((S[C1&255]&255) ^ ((S[(C2>>8)&255]&255)<<8) ^ ((S[(C3>>16)&255]&255)<<16) ^ (S[(C0>>24)&255]<<24)) ^ KW[r][1];
+            r2 = mcol((S[C2&255]&255) ^ ((S[(C3>>8)&255]&255)<<8) ^ ((S[(C0>>16)&255]&255)<<16) ^ (S[(C1>>24)&255]<<24)) ^ KW[r][2];
+            r3 = mcol((S[C3&255]&255) ^ ((S[(C0>>8)&255]&255)<<8) ^ ((S[(C1>>16)&255]&255)<<16) ^ (S[(C2>>24)&255]<<24)) ^ KW[r++][3];
+            C0 = mcol((S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24)) ^ KW[r][0];
+            C1 = mcol((S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24)) ^ KW[r][1];
+            C2 = mcol((S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24)) ^ KW[r][2];
+            C3 = mcol((S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24)) ^ KW[r++][3];
+        }
+
+        r0 = mcol((S[C0&255]&255) ^ ((S[(C1>>8)&255]&255)<<8) ^ ((S[(C2>>16)&255]&255)<<16) ^ (S[(C3>>24)&255]<<24)) ^ KW[r][0];
+        r1 = mcol((S[C1&255]&255) ^ ((S[(C2>>8)&255]&255)<<8) ^ ((S[(C3>>16)&255]&255)<<16) ^ (S[(C0>>24)&255]<<24)) ^ KW[r][1];
+        r2 = mcol((S[C2&255]&255) ^ ((S[(C3>>8)&255]&255)<<8) ^ ((S[(C0>>16)&255]&255)<<16) ^ (S[(C1>>24)&255]<<24)) ^ KW[r][2];
+        r3 = mcol((S[C3&255]&255) ^ ((S[(C0>>8)&255]&255)<<8) ^ ((S[(C1>>16)&255]&255)<<16) ^ (S[(C2>>24)&255]<<24)) ^ KW[r++][3];
+
+        // the final round is a simple function of S
+
+        C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r][0];
+        C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r][1];
+        C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r][2];
+        C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r][3];
+
+    }
+
+    private final void decryptBlock(int[][] KW)
+    {
+        int r, r0, r1, r2, r3;
+
+        C0 ^= KW[ROUNDS][0];
+        C1 ^= KW[ROUNDS][1];
+        C2 ^= KW[ROUNDS][2];
+        C3 ^= KW[ROUNDS][3];
+
+        for (r = ROUNDS-1; r>1;)
+        {
+            r0 = inv_mcol((Si[C0&255]&255) ^ ((Si[(C3>>8)&255]&255)<<8) ^ ((Si[(C2>>16)&255]&255)<<16) ^ (Si[(C1>>24)&255]<<24)) ^ KW[r][0];
+            r1 = inv_mcol((Si[C1&255]&255) ^ ((Si[(C0>>8)&255]&255)<<8) ^ ((Si[(C3>>16)&255]&255)<<16) ^ (Si[(C2>>24)&255]<<24)) ^ KW[r][1];
+            r2 = inv_mcol((Si[C2&255]&255) ^ ((Si[(C1>>8)&255]&255)<<8) ^ ((Si[(C0>>16)&255]&255)<<16) ^ (Si[(C3>>24)&255]<<24)) ^ KW[r][2];
+            r3 = inv_mcol((Si[C3&255]&255) ^ ((Si[(C2>>8)&255]&255)<<8) ^ ((Si[(C1>>16)&255]&255)<<16) ^ (Si[(C0>>24)&255]<<24)) ^ KW[r--][3];
+            C0 = inv_mcol((Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24)) ^ KW[r][0];
+            C1 = inv_mcol((Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24)) ^ KW[r][1];
+            C2 = inv_mcol((Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24)) ^ KW[r][2];
+            C3 = inv_mcol((Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24)) ^ KW[r--][3];
+        }
+
+        r0 = inv_mcol((Si[C0&255]&255) ^ ((Si[(C3>>8)&255]&255)<<8) ^ ((Si[(C2>>16)&255]&255)<<16) ^ (Si[(C1>>24)&255]<<24)) ^ KW[r][0];
+        r1 = inv_mcol((Si[C1&255]&255) ^ ((Si[(C0>>8)&255]&255)<<8) ^ ((Si[(C3>>16)&255]&255)<<16) ^ (Si[(C2>>24)&255]<<24)) ^ KW[r][1];
+        r2 = inv_mcol((Si[C2&255]&255) ^ ((Si[(C1>>8)&255]&255)<<8) ^ ((Si[(C0>>16)&255]&255)<<16) ^ (Si[(C3>>24)&255]<<24)) ^ KW[r][2];
+        r3 = inv_mcol((Si[C3&255]&255) ^ ((Si[(C2>>8)&255]&255)<<8) ^ ((Si[(C1>>16)&255]&255)<<16) ^ (Si[(C0>>24)&255]<<24)) ^ KW[r--][3];
+
+        // the final round's table is a simple function of Si
+
+        C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0][0];
+        C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0][1];
+        C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0][2];
+        C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0][3];
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/engines/AESWrapEngine.java b/libcore/security/src/main/java/org/bouncycastle/crypto/engines/AESWrapEngine.java
new file mode 100644
index 0000000..6f10eff
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/engines/AESWrapEngine.java
@@ -0,0 +1,167 @@
+package org.bouncycastle.crypto.engines;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.Wrapper;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * an implementation of the AES Key Wrapper from the NIST Key Wrap
+ * Specification.
+ * <p>
+ * For further details see: <a href="http://csrc.nist.gov/encryption/kms/key-wrap.pdf">http://csrc.nist.gov/encryption/kms/key-wrap.pdf</a>.
+ */
+public class AESWrapEngine
+    implements Wrapper
+{
+    private BlockCipher     engine = new AESEngine();
+    private KeyParameter    param;
+    private boolean         forWrapping;
+
+    private byte[]          iv = {
+                              (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6,
+                              (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6 };
+
+    public void init(
+        boolean             forWrapping,
+        CipherParameters    param)
+    {
+        this.forWrapping = forWrapping;
+
+        if (param instanceof KeyParameter)
+        {
+            this.param = (KeyParameter)param;
+        }
+        else if (param instanceof ParametersWithIV)
+        {
+            this.iv = ((ParametersWithIV) param).getIV();
+            this.param = (KeyParameter) ((ParametersWithIV) param).getParameters();
+            if (this.iv.length != 8)
+            {
+               throw new IllegalArgumentException("IV not multiple of 8");
+            }
+        }
+    }
+
+    public String getAlgorithmName()
+    {
+        return "AES";
+    }
+
+    public byte[] wrap(
+        byte[]  in,
+        int     inOff,
+        int     inLen)
+    {
+        if (!forWrapping)
+        {
+            throw new IllegalStateException("not set for wrapping");
+        }
+
+        int     n = inLen / 8;
+
+        if ((n * 8) != inLen)
+        {
+            throw new DataLengthException("wrap data must be a multiple of 8 bytes");
+        }
+
+        byte[]  block = new byte[inLen + iv.length];
+        byte[]  buf = new byte[8 + iv.length];
+
+        System.arraycopy(iv, 0, block, 0, iv.length);
+        System.arraycopy(in, 0, block, iv.length, inLen);
+
+        engine.init(true, param);
+
+        for (int j = 0; j != 6; j++)
+        {
+            for (int i = 1; i <= n; i++)
+            {
+                System.arraycopy(block, 0, buf, 0, iv.length);
+                System.arraycopy(block, 8 * i, buf, iv.length, 8);
+                engine.processBlock(buf, 0, buf, 0);
+
+                int t = n * j + i;
+                for (int k = 1; t != 0; k++)
+                {
+                    byte    v = (byte)t;
+
+                    buf[iv.length - k] ^= v;
+
+                    t >>>= 8;
+                }
+
+                System.arraycopy(buf, 0, block, 0, 8);
+                System.arraycopy(buf, 8, block, 8 * i, 8);
+            }
+        }
+
+        return block;
+    }
+
+    public byte[] unwrap(
+        byte[]  in,
+        int     inOff,
+        int     inLen)
+        throws InvalidCipherTextException
+    {
+        if (forWrapping)
+        {
+            throw new IllegalStateException("not set for unwrapping");
+        }
+
+        int     n = inLen / 8;
+
+        if ((n * 8) != inLen)
+        {
+            throw new InvalidCipherTextException("unwrap data must be a multiple of 8 bytes");
+        }
+
+        byte[]  block = new byte[inLen - iv.length];
+        byte[]  a = new byte[iv.length];
+        byte[]  buf = new byte[8 + iv.length];
+
+        System.arraycopy(in, 0, a, 0, iv.length);
+        System.arraycopy(in, iv.length, block, 0, inLen - iv.length);
+
+        engine.init(false, param);
+
+        n = n - 1;
+
+        for (int j = 5; j >= 0; j--)
+        {
+            for (int i = n; i >= 1; i--)
+            {
+                System.arraycopy(a, 0, buf, 0, iv.length);
+                System.arraycopy(block, 8 * (i - 1), buf, iv.length, 8);
+
+                int t = n * j + i;
+                for (int k = 1; t != 0; k++)
+                {
+                    byte    v = (byte)t;
+
+                    buf[iv.length - k] ^= v;
+
+                    t >>>= 8;
+                }
+
+                engine.processBlock(buf, 0, buf, 0);
+                System.arraycopy(buf, 0, a, 0, 8);
+                System.arraycopy(buf, 8, block, 8 * (i - 1), 8);
+            }
+        }
+
+        for (int i = 0; i != iv.length; i++)
+        {
+            if (a[i] != iv[i])
+            {
+                throw new InvalidCipherTextException("checksum failed");
+            }
+        }
+
+        return block;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/engines/DESEngine.java b/libcore/security/src/main/java/org/bouncycastle/crypto/engines/DESEngine.java
new file mode 100644
index 0000000..b795a9e
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/engines/DESEngine.java
@@ -0,0 +1,494 @@
+package org.bouncycastle.crypto.engines;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.KeyParameter;
+
+/**
+ * a class that provides a basic DES engine.
+ */
+public class DESEngine
+    implements BlockCipher
+{
+    protected static final int  BLOCK_SIZE = 8;
+
+    private int[]               workingKey = null;
+
+    /**
+     * standard constructor.
+     */
+    public DESEngine()
+    {
+    }
+
+    /**
+     * initialise a DES cipher.
+     *
+     * @param encrypting whether or not we are for encryption.
+     * @param params the parameters required to set up the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean           encrypting,
+        CipherParameters  params)
+    {
+        if (params instanceof KeyParameter)
+        {
+            if (((KeyParameter)params).getKey().length > 8)
+            {
+                throw new IllegalArgumentException("DES key too long - should be 8 bytes");
+            }
+            
+            workingKey = generateWorkingKey(encrypting,
+                                  ((KeyParameter)params).getKey());
+
+            return;
+        }
+
+        throw new IllegalArgumentException("invalid parameter passed to DES init - " + params.getClass().getName());
+    }
+
+    public String getAlgorithmName()
+    {
+        return "DES";
+    }
+
+    public int getBlockSize()
+    {
+        return BLOCK_SIZE;
+    }
+
+    public int processBlock(
+        byte[] in,
+        int inOff,
+        byte[] out,
+        int outOff)
+    {
+        if (workingKey == null)
+        {
+            throw new IllegalStateException("DES engine not initialised");
+        }
+
+        if ((inOff + BLOCK_SIZE) > in.length)
+        {
+            throw new DataLengthException("input buffer too short");
+        }
+
+        if ((outOff + BLOCK_SIZE) > out.length)
+        {
+            throw new DataLengthException("output buffer too short");
+        }
+
+        desFunc(workingKey, in, inOff, out, outOff);
+
+        return BLOCK_SIZE;
+    }
+
+    public void reset()
+    {
+    }
+
+    /**
+     * what follows is mainly taken from "Applied Cryptography", by
+     * Bruce Schneier, however it also bears great resemblance to Richard
+     * Outerbridge's D3DES...
+     */
+
+    static short[]    Df_Key =
+        {
+            0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,
+            0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,
+            0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67
+        };
+
+    static short[]    bytebit =
+        {
+            0200, 0100, 040, 020, 010, 04, 02, 01
+        };
+
+    static int[]    bigbyte =
+        {
+            0x800000, 0x400000, 0x200000, 0x100000,
+            0x80000,  0x40000,  0x20000,  0x10000,
+            0x8000,      0x4000,   0x2000,   0x1000,
+            0x800,    0x400,    0x200,    0x100,
+            0x80,      0x40,        0x20,     0x10,
+            0x8,      0x4,      0x2,      0x1
+        };
+
+    /*
+     * Use the key schedule specified in the Standard (ANSI X3.92-1981).
+     */
+
+    static byte[]    pc1 =
+        {
+            56, 48, 40, 32, 24, 16,  8,   0, 57, 49, 41, 33, 25, 17,
+             9,  1, 58, 50, 42, 34, 26,  18, 10,  2, 59, 51, 43, 35,
+            62, 54, 46, 38, 30, 22, 14,   6, 61, 53, 45, 37, 29, 21,
+            13,  5, 60, 52, 44, 36, 28,  20, 12,  4, 27, 19, 11,  3
+        };
+
+    static byte[] totrot =
+        {
+            1, 2, 4, 6, 8, 10, 12, 14,
+            15, 17, 19, 21, 23, 25, 27, 28
+        };
+
+    static byte[] pc2 =
+        {
+            13, 16, 10, 23,  0,  4,  2, 27, 14,  5, 20,  9,
+            22, 18, 11,  3, 25,  7, 15,  6, 26, 19, 12,  1,
+            40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
+            43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31
+        };
+
+    static int[] SP1 = {
+        0x01010400, 0x00000000, 0x00010000, 0x01010404,
+        0x01010004, 0x00010404, 0x00000004, 0x00010000,
+        0x00000400, 0x01010400, 0x01010404, 0x00000400,
+        0x01000404, 0x01010004, 0x01000000, 0x00000004,
+        0x00000404, 0x01000400, 0x01000400, 0x00010400,
+        0x00010400, 0x01010000, 0x01010000, 0x01000404,
+        0x00010004, 0x01000004, 0x01000004, 0x00010004,
+        0x00000000, 0x00000404, 0x00010404, 0x01000000,
+        0x00010000, 0x01010404, 0x00000004, 0x01010000,
+        0x01010400, 0x01000000, 0x01000000, 0x00000400,
+        0x01010004, 0x00010000, 0x00010400, 0x01000004,
+        0x00000400, 0x00000004, 0x01000404, 0x00010404,
+        0x01010404, 0x00010004, 0x01010000, 0x01000404,
+        0x01000004, 0x00000404, 0x00010404, 0x01010400,
+        0x00000404, 0x01000400, 0x01000400, 0x00000000,
+        0x00010004, 0x00010400, 0x00000000, 0x01010004
+    };
+
+    static int[] SP2 = {
+        0x80108020, 0x80008000, 0x00008000, 0x00108020,
+        0x00100000, 0x00000020, 0x80100020, 0x80008020,
+        0x80000020, 0x80108020, 0x80108000, 0x80000000,
+        0x80008000, 0x00100000, 0x00000020, 0x80100020,
+        0x00108000, 0x00100020, 0x80008020, 0x00000000,
+        0x80000000, 0x00008000, 0x00108020, 0x80100000,
+        0x00100020, 0x80000020, 0x00000000, 0x00108000,
+        0x00008020, 0x80108000, 0x80100000, 0x00008020,
+        0x00000000, 0x00108020, 0x80100020, 0x00100000,
+        0x80008020, 0x80100000, 0x80108000, 0x00008000,
+        0x80100000, 0x80008000, 0x00000020, 0x80108020,
+        0x00108020, 0x00000020, 0x00008000, 0x80000000,
+        0x00008020, 0x80108000, 0x00100000, 0x80000020,
+        0x00100020, 0x80008020, 0x80000020, 0x00100020,
+        0x00108000, 0x00000000, 0x80008000, 0x00008020,
+        0x80000000, 0x80100020, 0x80108020, 0x00108000
+    };
+
+    static int[] SP3 = {
+        0x00000208, 0x08020200, 0x00000000, 0x08020008,
+        0x08000200, 0x00000000, 0x00020208, 0x08000200,
+        0x00020008, 0x08000008, 0x08000008, 0x00020000,
+        0x08020208, 0x00020008, 0x08020000, 0x00000208,
+        0x08000000, 0x00000008, 0x08020200, 0x00000200,
+        0x00020200, 0x08020000, 0x08020008, 0x00020208,
+        0x08000208, 0x00020200, 0x00020000, 0x08000208,
+        0x00000008, 0x08020208, 0x00000200, 0x08000000,
+        0x08020200, 0x08000000, 0x00020008, 0x00000208,
+        0x00020000, 0x08020200, 0x08000200, 0x00000000,
+        0x00000200, 0x00020008, 0x08020208, 0x08000200,
+        0x08000008, 0x00000200, 0x00000000, 0x08020008,
+        0x08000208, 0x00020000, 0x08000000, 0x08020208,
+        0x00000008, 0x00020208, 0x00020200, 0x08000008,
+        0x08020000, 0x08000208, 0x00000208, 0x08020000,
+        0x00020208, 0x00000008, 0x08020008, 0x00020200
+    };
+
+    static int[] SP4 = {
+        0x00802001, 0x00002081, 0x00002081, 0x00000080,
+        0x00802080, 0x00800081, 0x00800001, 0x00002001,
+        0x00000000, 0x00802000, 0x00802000, 0x00802081,
+        0x00000081, 0x00000000, 0x00800080, 0x00800001,
+        0x00000001, 0x00002000, 0x00800000, 0x00802001,
+        0x00000080, 0x00800000, 0x00002001, 0x00002080,
+        0x00800081, 0x00000001, 0x00002080, 0x00800080,
+        0x00002000, 0x00802080, 0x00802081, 0x00000081,
+        0x00800080, 0x00800001, 0x00802000, 0x00802081,
+        0x00000081, 0x00000000, 0x00000000, 0x00802000,
+        0x00002080, 0x00800080, 0x00800081, 0x00000001,
+        0x00802001, 0x00002081, 0x00002081, 0x00000080,
+        0x00802081, 0x00000081, 0x00000001, 0x00002000,
+        0x00800001, 0x00002001, 0x00802080, 0x00800081,
+        0x00002001, 0x00002080, 0x00800000, 0x00802001,
+        0x00000080, 0x00800000, 0x00002000, 0x00802080
+    };
+
+    static int[] SP5 = {
+        0x00000100, 0x02080100, 0x02080000, 0x42000100,
+        0x00080000, 0x00000100, 0x40000000, 0x02080000,
+        0x40080100, 0x00080000, 0x02000100, 0x40080100,
+        0x42000100, 0x42080000, 0x00080100, 0x40000000,
+        0x02000000, 0x40080000, 0x40080000, 0x00000000,
+        0x40000100, 0x42080100, 0x42080100, 0x02000100,
+        0x42080000, 0x40000100, 0x00000000, 0x42000000,
+        0x02080100, 0x02000000, 0x42000000, 0x00080100,
+        0x00080000, 0x42000100, 0x00000100, 0x02000000,
+        0x40000000, 0x02080000, 0x42000100, 0x40080100,
+        0x02000100, 0x40000000, 0x42080000, 0x02080100,
+        0x40080100, 0x00000100, 0x02000000, 0x42080000,
+        0x42080100, 0x00080100, 0x42000000, 0x42080100,
+        0x02080000, 0x00000000, 0x40080000, 0x42000000,
+        0x00080100, 0x02000100, 0x40000100, 0x00080000,
+        0x00000000, 0x40080000, 0x02080100, 0x40000100
+    };
+
+    static int[] SP6 = {
+        0x20000010, 0x20400000, 0x00004000, 0x20404010,
+        0x20400000, 0x00000010, 0x20404010, 0x00400000,
+        0x20004000, 0x00404010, 0x00400000, 0x20000010,
+        0x00400010, 0x20004000, 0x20000000, 0x00004010,
+        0x00000000, 0x00400010, 0x20004010, 0x00004000,
+        0x00404000, 0x20004010, 0x00000010, 0x20400010,
+        0x20400010, 0x00000000, 0x00404010, 0x20404000,
+        0x00004010, 0x00404000, 0x20404000, 0x20000000,
+        0x20004000, 0x00000010, 0x20400010, 0x00404000,
+        0x20404010, 0x00400000, 0x00004010, 0x20000010,
+        0x00400000, 0x20004000, 0x20000000, 0x00004010,
+        0x20000010, 0x20404010, 0x00404000, 0x20400000,
+        0x00404010, 0x20404000, 0x00000000, 0x20400010,
+        0x00000010, 0x00004000, 0x20400000, 0x00404010,
+        0x00004000, 0x00400010, 0x20004010, 0x00000000,
+        0x20404000, 0x20000000, 0x00400010, 0x20004010
+    };
+
+    static int[] SP7 = {
+        0x00200000, 0x04200002, 0x04000802, 0x00000000,
+        0x00000800, 0x04000802, 0x00200802, 0x04200800,
+        0x04200802, 0x00200000, 0x00000000, 0x04000002,
+        0x00000002, 0x04000000, 0x04200002, 0x00000802,
+        0x04000800, 0x00200802, 0x00200002, 0x04000800,
+        0x04000002, 0x04200000, 0x04200800, 0x00200002,
+        0x04200000, 0x00000800, 0x00000802, 0x04200802,
+        0x00200800, 0x00000002, 0x04000000, 0x00200800,
+        0x04000000, 0x00200800, 0x00200000, 0x04000802,
+        0x04000802, 0x04200002, 0x04200002, 0x00000002,
+        0x00200002, 0x04000000, 0x04000800, 0x00200000,
+        0x04200800, 0x00000802, 0x00200802, 0x04200800,
+        0x00000802, 0x04000002, 0x04200802, 0x04200000,
+        0x00200800, 0x00000000, 0x00000002, 0x04200802,
+        0x00000000, 0x00200802, 0x04200000, 0x00000800,
+        0x04000002, 0x04000800, 0x00000800, 0x00200002
+    };
+
+    static int[] SP8 = {
+        0x10001040, 0x00001000, 0x00040000, 0x10041040,
+        0x10000000, 0x10001040, 0x00000040, 0x10000000,
+        0x00040040, 0x10040000, 0x10041040, 0x00041000,
+        0x10041000, 0x00041040, 0x00001000, 0x00000040,
+        0x10040000, 0x10000040, 0x10001000, 0x00001040,
+        0x00041000, 0x00040040, 0x10040040, 0x10041000,
+        0x00001040, 0x00000000, 0x00000000, 0x10040040,
+        0x10000040, 0x10001000, 0x00041040, 0x00040000,
+        0x00041040, 0x00040000, 0x10041000, 0x00001000,
+        0x00000040, 0x10040040, 0x00001000, 0x00041040,
+        0x10001000, 0x00000040, 0x10000040, 0x10040000,
+        0x10040040, 0x10000000, 0x00040000, 0x10001040,
+        0x00000000, 0x10041040, 0x00040040, 0x10000040,
+        0x10040000, 0x10001000, 0x10001040, 0x00000000,
+        0x10041040, 0x00041000, 0x00041000, 0x00001040,
+        0x00001040, 0x00040040, 0x10000000, 0x10041000
+    };
+
+    /**
+     * generate an integer based working key based on our secret key
+     * and what we processing we are planning to do.
+     *
+     * Acknowledgements for this routine go to James Gillogly & Phil Karn.
+     *         (whoever, and wherever they are!).
+     */
+    protected int[] generateWorkingKey(
+        boolean encrypting,
+        byte[]  key)
+    {
+        int[]       newKey = new int[32];
+        boolean[]   pc1m = new boolean[56],
+                    pcr = new boolean[56];
+
+        for (int j = 0; j < 56; j++)
+        {
+            int    l = pc1[j];
+
+            pc1m[j] = ((key[l >>> 3] & bytebit[l & 07]) != 0);
+        }
+
+        for (int i = 0; i < 16; i++)
+        {
+            int    l, m, n;
+
+            if (encrypting)
+            {
+                m = i << 1;
+            }
+            else
+            {
+                m = (15 - i) << 1;
+            }
+
+            n = m + 1;
+            newKey[m] = newKey[n] = 0;
+
+            for (int j = 0; j < 28; j++)
+            {
+                l = j + totrot[i];
+                if (l < 28)
+                {
+                    pcr[j] = pc1m[l];
+                }
+                else
+                {
+                    pcr[j] = pc1m[l - 28];
+                }
+            }
+
+            for (int j = 28; j < 56; j++)
+            {
+                l = j + totrot[i];
+                if (l < 56)
+                {
+                    pcr[j] = pc1m[l];
+                }
+                else
+                {
+                    pcr[j] = pc1m[l - 28];
+                }
+            }
+
+            for (int j = 0; j < 24; j++)
+            {
+                if (pcr[pc2[j]])
+                {
+                    newKey[m] |= bigbyte[j];
+                }
+
+                if (pcr[pc2[j + 24]])
+                {
+                    newKey[n] |= bigbyte[j];
+                }
+            }
+        }
+
+        //
+        // store the processed key
+        //
+        for (int i = 0; i != 32; i += 2)
+        {
+            int    i1, i2;
+
+            i1 = newKey[i];
+            i2 = newKey[i + 1];
+
+            newKey[i] = ((i1 & 0x00fc0000) << 6) | ((i1 & 0x00000fc0) << 10)
+                                   | ((i2 & 0x00fc0000) >>> 10) | ((i2 & 0x00000fc0) >>> 6);
+
+            newKey[i + 1] = ((i1 & 0x0003f000) << 12) | ((i1 & 0x0000003f) << 16)
+                                   | ((i2 & 0x0003f000) >>> 4) | (i2 & 0x0000003f);
+        }
+
+        return newKey;
+    }
+
+    /**
+     * the DES engine.
+     */
+    protected void desFunc(
+        int[]   wKey,
+        byte[]  in,
+        int     inOff,
+        byte[]  out,
+        int     outOff)
+    {
+        int     work, right, left;
+
+        left     = (in[inOff + 0] & 0xff) << 24;
+        left    |= (in[inOff + 1] & 0xff) << 16;
+        left    |= (in[inOff + 2] & 0xff) << 8;
+        left    |= (in[inOff + 3] & 0xff);
+
+        right     = (in[inOff + 4] & 0xff) << 24;
+        right    |= (in[inOff + 5] & 0xff) << 16;
+        right    |= (in[inOff + 6] & 0xff) << 8;
+        right    |= (in[inOff + 7] & 0xff);
+
+        work = ((left >>> 4) ^ right) & 0x0f0f0f0f;
+        right ^= work;
+        left ^= (work << 4);
+        work = ((left >>> 16) ^ right) & 0x0000ffff;
+        right ^= work;
+        left ^= (work << 16);
+        work = ((right >>> 2) ^ left) & 0x33333333;
+        left ^= work;
+        right ^= (work << 2);
+        work = ((right >>> 8) ^ left) & 0x00ff00ff;
+        left ^= work;
+        right ^= (work << 8);
+        right = ((right << 1) | ((right >>> 31) & 1)) & 0xffffffff;
+        work = (left ^ right) & 0xaaaaaaaa;
+        left ^= work;
+        right ^= work;
+        left = ((left << 1) | ((left >>> 31) & 1)) & 0xffffffff;
+
+        for (int round = 0; round < 8; round++)
+        {
+            int     fval;
+
+            work  = (right << 28) | (right >>> 4);
+            work ^= wKey[round * 4 + 0];
+            fval  = SP7[ work      & 0x3f];
+            fval |= SP5[(work >>>  8) & 0x3f];
+            fval |= SP3[(work >>> 16) & 0x3f];
+            fval |= SP1[(work >>> 24) & 0x3f];
+            work  = right ^ wKey[round * 4 + 1];
+            fval |= SP8[ work      & 0x3f];
+            fval |= SP6[(work >>>  8) & 0x3f];
+            fval |= SP4[(work >>> 16) & 0x3f];
+            fval |= SP2[(work >>> 24) & 0x3f];
+            left ^= fval;
+            work  = (left << 28) | (left >>> 4);
+            work ^= wKey[round * 4 + 2];
+            fval  = SP7[ work      & 0x3f];
+            fval |= SP5[(work >>>  8) & 0x3f];
+            fval |= SP3[(work >>> 16) & 0x3f];
+            fval |= SP1[(work >>> 24) & 0x3f];
+            work  = left ^ wKey[round * 4 + 3];
+            fval |= SP8[ work      & 0x3f];
+            fval |= SP6[(work >>>  8) & 0x3f];
+            fval |= SP4[(work >>> 16) & 0x3f];
+            fval |= SP2[(work >>> 24) & 0x3f];
+            right ^= fval;
+        }
+
+        right = (right << 31) | (right >>> 1);
+        work = (left ^ right) & 0xaaaaaaaa;
+        left ^= work;
+        right ^= work;
+        left = (left << 31) | (left >>> 1);
+        work = ((left >>> 8) ^ right) & 0x00ff00ff;
+        right ^= work;
+        left ^= (work << 8);
+        work = ((left >>> 2) ^ right) & 0x33333333;
+        right ^= work;
+        left ^= (work << 2);
+        work = ((right >>> 16) ^ left) & 0x0000ffff;
+        left ^= work;
+        right ^= (work << 16);
+        work = ((right >>> 4) ^ left) & 0x0f0f0f0f;
+        left ^= work;
+        right ^= (work << 4);
+
+        out[outOff + 0] = (byte)((right >>> 24) & 0xff);
+        out[outOff + 1] = (byte)((right >>> 16) & 0xff);
+        out[outOff + 2] = (byte)((right >>>  8) & 0xff);
+        out[outOff + 3] = (byte)(right         & 0xff);
+        out[outOff + 4] = (byte)((left >>> 24) & 0xff);
+        out[outOff + 5] = (byte)((left >>> 16) & 0xff);
+        out[outOff + 6] = (byte)((left >>>  8) & 0xff);
+        out[outOff + 7] = (byte)(left         & 0xff);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/engines/DESedeEngine.java b/libcore/security/src/main/java/org/bouncycastle/crypto/engines/DESedeEngine.java
new file mode 100644
index 0000000..a340034
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/engines/DESedeEngine.java
@@ -0,0 +1,126 @@
+package org.bouncycastle.crypto.engines;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.KeyParameter;
+
+/**
+ * a class that provides a basic DESede (or Triple DES) engine.
+ */
+public class DESedeEngine
+    extends DESEngine
+{
+    protected static final int  BLOCK_SIZE = 8;
+
+    private int[]               workingKey1 = null;
+    private int[]               workingKey2 = null;
+    private int[]               workingKey3 = null;
+
+    private boolean             forEncryption;
+
+    /**
+     * standard constructor.
+     */
+    public DESedeEngine()
+    {
+    }
+
+    /**
+     * initialise a DESede cipher.
+     *
+     * @param encrypting whether or not we are for encryption.
+     * @param params the parameters required to set up the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean           encrypting,
+        CipherParameters  params)
+    {
+        if (!(params instanceof KeyParameter))
+        {
+            throw new IllegalArgumentException("invalid parameter passed to DESede init - " + params.getClass().getName());
+        }
+
+        byte[]      keyMaster = ((KeyParameter)params).getKey();
+        byte[]      key1 = new byte[8], key2 = new byte[8], key3 = new byte[8];
+
+        if (keyMaster.length > 24)
+        {
+            throw new IllegalArgumentException("key size greater than 24 bytes");
+        }
+        
+        this.forEncryption = encrypting;
+
+        if (keyMaster.length == 24)
+        {
+            System.arraycopy(keyMaster, 0, key1, 0, key1.length);
+            System.arraycopy(keyMaster, 8, key2, 0, key2.length);
+            System.arraycopy(keyMaster, 16, key3, 0, key3.length);
+
+            workingKey1 = generateWorkingKey(encrypting, key1);
+            workingKey2 = generateWorkingKey(!encrypting, key2);
+            workingKey3 = generateWorkingKey(encrypting, key3);
+        }
+        else    // 16 byte key
+        {
+            System.arraycopy(keyMaster, 0, key1, 0, key1.length);
+            System.arraycopy(keyMaster, 8, key2, 0, key2.length);
+
+            workingKey1 = generateWorkingKey(encrypting, key1);
+            workingKey2 = generateWorkingKey(!encrypting, key2);
+            workingKey3 = workingKey1;
+        }
+    }
+
+    public String getAlgorithmName()
+    {
+        return "DESede";
+    }
+
+    public int getBlockSize()
+    {
+        return BLOCK_SIZE;
+    }
+
+    public int processBlock(
+        byte[] in,
+        int inOff,
+        byte[] out,
+        int outOff)
+    {
+        if (workingKey1 == null)
+        {
+            throw new IllegalStateException("DESede engine not initialised");
+        }
+
+        if ((inOff + BLOCK_SIZE) > in.length)
+        {
+            throw new DataLengthException("input buffer too short");
+        }
+
+        if ((outOff + BLOCK_SIZE) > out.length)
+        {
+            throw new DataLengthException("output buffer too short");
+        }
+
+        if (forEncryption)
+        {
+            desFunc(workingKey1, in, inOff, out, outOff);
+            desFunc(workingKey2, out, outOff, out, outOff);
+            desFunc(workingKey3, out, outOff, out, outOff);
+        }
+        else
+        {
+            desFunc(workingKey3, in, inOff, out, outOff);
+            desFunc(workingKey2, out, outOff, out, outOff);
+            desFunc(workingKey1, out, outOff, out, outOff);
+        }
+
+        return BLOCK_SIZE;
+    }
+
+    public void reset()
+    {
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java b/libcore/security/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java
new file mode 100644
index 0000000..e37244b
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java
@@ -0,0 +1,366 @@
+package org.bouncycastle.crypto.engines;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.Wrapper;
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * Wrap keys according to
+ * <A HREF="http://www.ietf.org/internet-drafts/draft-ietf-smime-key-wrap-01.txt">
+ * draft-ietf-smime-key-wrap-01.txt</A>.
+ * <p>
+ * Note: 
+ * <ul>
+ * <li>this is based on a draft, and as such is subject to change - don't use this class for anything requiring long term storage.
+ * <li>if you are using this to wrap triple-des keys you need to set the
+ * parity bits on the key and, if it's a two-key triple-des key, pad it
+ * yourself.
+ * </ul>
+ */
+public class DESedeWrapEngine
+    implements Wrapper
+{
+   /** Field engine */
+   private CBCBlockCipher engine;
+
+   /** Field param */
+   private KeyParameter param;
+
+   /** Field paramPlusIV */
+   private ParametersWithIV paramPlusIV;
+
+   /** Field iv */
+   private byte[] iv;
+
+   /** Field forWrapping */
+   private boolean forWrapping;
+
+   /** Field IV2           */
+   private static final byte[] IV2 = { (byte) 0x4a, (byte) 0xdd, (byte) 0xa2,
+                                       (byte) 0x2c, (byte) 0x79, (byte) 0xe8,
+                                       (byte) 0x21, (byte) 0x05 };
+
+    //
+    // checksum digest
+    //
+    Digest  sha1 = new SHA1Digest();
+    byte[]  digest = new byte[20];
+
+   /**
+    * Method init
+    *
+    * @param forWrapping
+    * @param param
+    */
+    public void init(boolean forWrapping, CipherParameters param)
+    {
+
+        this.forWrapping = forWrapping;
+        this.engine = new CBCBlockCipher(new DESedeEngine());
+
+        if (param instanceof KeyParameter)
+        {
+            this.param = (KeyParameter)param;
+
+            if (this.forWrapping)
+            {
+
+                // Hm, we have no IV but we want to wrap ?!?
+                // well, then we have to create our own IV.
+                this.iv = new byte[8];
+
+                SecureRandom sr = new SecureRandom();
+
+                sr.nextBytes(iv);
+
+                this.paramPlusIV = new ParametersWithIV(this.param, this.iv);
+            }
+        }
+        else if (param instanceof ParametersWithIV)
+        {
+            this.paramPlusIV = (ParametersWithIV)param;
+            this.iv = this.paramPlusIV.getIV();
+            this.param = (KeyParameter)this.paramPlusIV.getParameters();
+
+            if (this.forWrapping)
+            {
+                if ((this.iv == null) || (this.iv.length != 8))
+                {
+                    throw new IllegalArgumentException("IV is not 8 octets");
+                }
+            }
+            else
+            {
+                throw new IllegalArgumentException(
+                        "You should not supply an IV for unwrapping");
+            }
+        }
+    }
+
+   /**
+    * Method getAlgorithmName
+    *
+    * @return the algorithm name "DESede".
+    */
+   public String getAlgorithmName() 
+   {
+      return "DESede";
+   }
+
+   /**
+    * Method wrap
+    *
+    * @param in
+    * @param inOff
+    * @param inLen
+    * @return the wrapped bytes.
+    */
+   public byte[] wrap(byte[] in, int inOff, int inLen) 
+   {
+      if (!forWrapping) 
+      {
+         throw new IllegalStateException("Not initialized for wrapping");
+      }
+
+      byte keyToBeWrapped[] = new byte[inLen];
+
+      System.arraycopy(in, inOff, keyToBeWrapped, 0, inLen);
+
+      // Compute the CMS Key Checksum, (section 5.6.1), call this CKS.
+      byte[] CKS = calculateCMSKeyChecksum(keyToBeWrapped);
+
+      // Let WKCKS = WK || CKS where || is concatenation.
+      byte[] WKCKS = new byte[keyToBeWrapped.length + CKS.length];
+
+      System.arraycopy(keyToBeWrapped, 0, WKCKS, 0, keyToBeWrapped.length);
+      System.arraycopy(CKS, 0, WKCKS, keyToBeWrapped.length, CKS.length);
+
+      // Encrypt WKCKS in CBC mode using KEK as the key and IV as the
+      // initialization vector. Call the results TEMP1.
+      byte TEMP1[] = new byte[WKCKS.length];
+
+      System.arraycopy(WKCKS, 0, TEMP1, 0, WKCKS.length);
+
+      int noOfBlocks = WKCKS.length / engine.getBlockSize();
+      int extraBytes = WKCKS.length % engine.getBlockSize();
+
+      if (extraBytes != 0) 
+      {
+         throw new IllegalStateException("Not multiple of block length");
+      }
+
+      engine.init(true, paramPlusIV);
+
+      for (int i = 0; i < noOfBlocks; i++) 
+      {
+         int currentBytePos = i * engine.getBlockSize();
+
+         engine.processBlock(TEMP1, currentBytePos, TEMP1, currentBytePos);
+      }
+
+      // Left TEMP2 = IV || TEMP1.
+      byte[] TEMP2 = new byte[this.iv.length + TEMP1.length];
+
+      System.arraycopy(this.iv, 0, TEMP2, 0, this.iv.length);
+      System.arraycopy(TEMP1, 0, TEMP2, this.iv.length, TEMP1.length);
+
+      // Reverse the order of the octets in TEMP2 and call the result TEMP3.
+      byte[] TEMP3 = new byte[TEMP2.length];
+
+      for (int i = 0; i < TEMP2.length; i++) 
+      {
+         TEMP3[i] = TEMP2[TEMP2.length - (i + 1)];
+      }
+
+      // Encrypt TEMP3 in CBC mode using the KEK and an initialization vector
+      // of 0x 4a dd a2 2c 79 e8 21 05. The resulting cipher text is the desired
+      // result. It is 40 octets long if a 168 bit key is being wrapped.
+      ParametersWithIV param2 = new ParametersWithIV(this.param, IV2);
+
+      this.engine.init(true, param2);
+
+      for (int i = 0; i < noOfBlocks + 1; i++) 
+      {
+         int currentBytePos = i * engine.getBlockSize();
+
+         engine.processBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
+      }
+
+      return TEMP3;
+   }
+
+   /**
+    * Method unwrap
+    *
+    * @param in
+    * @param inOff
+    * @param inLen
+    * @return the unwrapped bytes.
+    * @throws InvalidCipherTextException
+    */
+    public byte[] unwrap(byte[] in, int inOff, int inLen)
+           throws InvalidCipherTextException 
+    {
+        if (forWrapping)
+        {
+            throw new IllegalStateException("Not set for unwrapping");
+        }
+        
+        if (in == null)
+        {
+            throw new InvalidCipherTextException("Null pointer as ciphertext");
+        }
+        
+        if (inLen % engine.getBlockSize() != 0)
+        {
+            throw new InvalidCipherTextException("Ciphertext not multiple of "
+                    + engine.getBlockSize());
+        }
+
+      /*
+      // Check if the length of the cipher text is reasonable given the key
+      // type. It must be 40 bytes for a 168 bit key and either 32, 40, or
+      // 48 bytes for a 128, 192, or 256 bit key. If the length is not supported
+      // or inconsistent with the algorithm for which the key is intended,
+      // return error.
+      //
+      // we do not accept 168 bit keys. it has to be 192 bit.
+      int lengthA = (estimatedKeyLengthInBit / 8) + 16;
+      int lengthB = estimatedKeyLengthInBit % 8;
+
+      if ((lengthA != keyToBeUnwrapped.length) || (lengthB != 0)) {
+         throw new XMLSecurityException("empty");
+      }
+      */
+
+      // Decrypt the cipher text with TRIPLedeS in CBC mode using the KEK
+      // and an initialization vector (IV) of 0x4adda22c79e82105. Call the output TEMP3.
+      ParametersWithIV param2 = new ParametersWithIV(this.param, IV2);
+
+      this.engine.init(false, param2);
+
+      byte TEMP3[] = new byte[inLen];
+
+      System.arraycopy(in, inOff, TEMP3, 0, inLen);
+
+      for (int i = 0; i < (TEMP3.length / engine.getBlockSize()); i++) 
+      {
+         int currentBytePos = i * engine.getBlockSize();
+
+         engine.processBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
+      }
+
+      // Reverse the order of the octets in TEMP3 and call the result TEMP2.
+      byte[] TEMP2 = new byte[TEMP3.length];
+
+      for (int i = 0; i < TEMP3.length; i++) 
+      {
+         TEMP2[i] = TEMP3[TEMP3.length - (i + 1)];
+      }
+
+      // Decompose TEMP2 into IV, the first 8 octets, and TEMP1, the remaining octets.
+      this.iv = new byte[8];
+
+      byte[] TEMP1 = new byte[TEMP2.length - 8];
+
+      System.arraycopy(TEMP2, 0, this.iv, 0, 8);
+      System.arraycopy(TEMP2, 8, TEMP1, 0, TEMP2.length - 8);
+
+      // Decrypt TEMP1 using TRIPLedeS in CBC mode using the KEK and the IV
+      // found in the previous step. Call the result WKCKS.
+      this.paramPlusIV = new ParametersWithIV(this.param, this.iv);
+
+      this.engine.init(false, this.paramPlusIV);
+
+      byte[] WKCKS = new byte[TEMP1.length];
+
+      System.arraycopy(TEMP1, 0, WKCKS, 0, TEMP1.length);
+
+      for (int i = 0; i < (WKCKS.length / engine.getBlockSize()); i++) 
+      {
+         int currentBytePos = i * engine.getBlockSize();
+
+         engine.processBlock(WKCKS, currentBytePos, WKCKS, currentBytePos);
+      }
+
+      // Decompose WKCKS. CKS is the last 8 octets and WK, the wrapped key, are
+      // those octets before the CKS.
+      byte[] result = new byte[WKCKS.length - 8];
+      byte[] CKStoBeVerified = new byte[8];
+
+      System.arraycopy(WKCKS, 0, result, 0, WKCKS.length - 8);
+      System.arraycopy(WKCKS, WKCKS.length - 8, CKStoBeVerified, 0, 8);
+
+      // Calculate a CMS Key Checksum, (section 5.6.1), over the WK and compare
+      // with the CKS extracted in the above step. If they are not equal, return error.
+      if (!checkCMSKeyChecksum(result, CKStoBeVerified)) 
+      {
+         throw new InvalidCipherTextException(
+            "Checksum inside ciphertext is corrupted");
+      }
+
+      // WK is the wrapped key, now extracted for use in data decryption.
+      return result;
+   }
+
+    /**
+     * Some key wrap algorithms make use of the Key Checksum defined
+     * in CMS [CMS-Algorithms]. This is used to provide an integrity
+     * check value for the key being wrapped. The algorithm is
+     *
+     * - Compute the 20 octet SHA-1 hash on the key being wrapped.
+     * - Use the first 8 octets of this hash as the checksum value.
+     *
+     * @param key
+     * @return the CMS checksum.
+     * @throws RuntimeException
+     * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+     */
+    private byte[] calculateCMSKeyChecksum(
+        byte[] key)
+    {
+        byte[]  result = new byte[8];
+
+        sha1.update(key, 0, key.length);
+        sha1.doFinal(digest, 0);
+
+        System.arraycopy(digest, 0, result, 0, 8);
+
+        return result;
+    }
+
+    /**
+     * @param key
+     * @param checksum
+     * @return true if okay, false otherwise.
+     * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+     */
+    private boolean checkCMSKeyChecksum(
+        byte[] key,
+        byte[] checksum)
+    {
+        byte[] calculatedChecksum = calculateCMSKeyChecksum(key);
+
+        if (checksum.length != calculatedChecksum.length)
+        {
+            return false;
+        }
+
+        for (int i = 0; i != checksum.length; i++)
+        {
+            if (checksum[i] != calculatedChecksum[i])
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/engines/IESEngine.java b/libcore/security/src/main/java/org/bouncycastle/crypto/engines/IESEngine.java
new file mode 100644
index 0000000..723fd9a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/engines/IESEngine.java
@@ -0,0 +1,245 @@
+package org.bouncycastle.crypto.engines;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.crypto.BasicAgreement;
+import org.bouncycastle.crypto.BufferedBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DerivationFunction;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.params.IESParameters;
+import org.bouncycastle.crypto.params.IESWithCipherParameters;
+import org.bouncycastle.crypto.params.KDFParameters;
+import org.bouncycastle.crypto.params.KeyParameter;
+
+/**
+ * support class for constructing intergrated encryption ciphers
+ * for doing basic message exchanges on top of key agreement ciphers
+ */
+public class IESEngine
+{
+    BasicAgreement      agree;
+    DerivationFunction  kdf;
+    Mac                 mac;
+    BufferedBlockCipher cipher;
+    byte[]              macBuf;
+
+    boolean             forEncryption;
+    CipherParameters    privParam, pubParam;
+    IESParameters       param;
+
+    /**
+     * set up for use with stream mode, where the key derivation function
+     * is used to provide a stream of bytes to xor with the message.
+     *
+     * @param agree the key agreement used as the basis for the encryption
+     * @param kdf the key derivation function used for byte generation
+     * @param mac the message authentication code generator for the message
+     */
+    public IESEngine(
+        BasicAgreement      agree,
+        DerivationFunction  kdf,
+        Mac                 mac)
+    {
+        this.agree = agree;
+        this.kdf = kdf;
+        this.mac = mac;
+        this.macBuf = new byte[mac.getMacSize()];
+        this.cipher = null;
+    }
+
+    /**
+     * set up for use in conjunction with a block cipher to handle the
+     * message.
+     *
+     * @param agree the key agreement used as the basis for the encryption
+     * @param kdf the key derivation function used for byte generation
+     * @param mac the message authentication code generator for the message
+     * @param cipher the cipher to used for encrypting the message
+     */
+    public IESEngine(
+        BasicAgreement      agree,
+        DerivationFunction  kdf,
+        Mac                 mac,
+        BufferedBlockCipher cipher)
+    {
+        this.agree = agree;
+        this.kdf = kdf;
+        this.mac = mac;
+        this.macBuf = new byte[mac.getMacSize()];
+        this.cipher = cipher;
+    }
+
+    /**
+     * Initialise the encryptor.
+     *
+     * @param forEncryption whether or not this is encryption/decryption.
+     * @param privParam our private key parameters
+     * @param pubParam the recipient's/sender's public key parameters
+     * @param param encoding and derivation parameters.
+     */
+    public void init(
+        boolean                     forEncryption,
+        CipherParameters            privParam,
+        CipherParameters            pubParam,
+        CipherParameters            param)
+    {
+        this.forEncryption = forEncryption;
+        this.privParam = privParam;
+        this.pubParam = pubParam;
+        this.param = (IESParameters)param;
+    }
+
+    private byte[] decryptBlock(
+        byte[]  in_enc,
+        int     inOff,
+        int     inLen,
+        byte[]  z)
+        throws InvalidCipherTextException
+    {
+        byte[]          M = null;
+        KeyParameter    macKey = null;
+        KDFParameters   kParam = new KDFParameters(z, param.getDerivationV());
+        int             macKeySize = param.getMacKeySize();
+
+        kdf.init(kParam);
+
+        inLen -= mac.getMacSize();
+    
+        if (cipher == null)     // stream mode
+        {
+            byte[]  buf = new byte[inLen + (macKeySize / 8)];
+
+            M = new byte[inLen];
+
+            kdf.generateBytes(buf, 0, buf.length);
+
+            for (int i = 0; i != inLen; i++)
+            {
+                M[i] = (byte)(in_enc[inOff + i] ^ buf[i]);
+            }
+
+            macKey = new KeyParameter(buf, inLen, (macKeySize / 8));
+        }
+        else
+        {
+            int     cipherKeySize = ((IESWithCipherParameters)param).getCipherKeySize();
+            byte[]  buf = new byte[(cipherKeySize / 8) + (macKeySize / 8)];
+
+            cipher.init(false, new KeyParameter(buf, 0, (cipherKeySize / 8)));
+
+            byte[] tmp = new byte[cipher.getOutputSize(inLen)];
+
+            int off = cipher.processBytes(in_enc, inOff, inLen, tmp, 0);
+
+            off += cipher.doFinal(tmp, off);
+
+            M = new byte[off];
+
+            System.arraycopy(tmp, 0, M, 0, off);
+
+            macKey = new KeyParameter(buf, (cipherKeySize / 8), (macKeySize / 8));
+        }
+
+        byte[]  macIV = param.getEncodingV();
+
+        mac.init(macKey);
+        mac.update(in_enc, inOff, inLen);
+        mac.update(macIV, 0, macIV.length);
+        mac.doFinal(macBuf, 0);
+    
+        inOff += inLen;
+
+        for (int t = 0; t < macBuf.length; t++)
+        {           
+            if (macBuf[t] != in_enc[inOff + t])
+            {
+                throw (new InvalidCipherTextException("Mac codes failed to equal."));
+            }
+        }
+       
+        return M;
+    }
+
+    private byte[] encryptBlock(
+        byte[]  in,
+        int     inOff,
+        int     inLen,
+        byte[]  z)
+        throws InvalidCipherTextException
+    {
+        byte[]          C = null;
+        KeyParameter    macKey = null;
+        KDFParameters   kParam = new KDFParameters(z, param.getDerivationV());
+        int             c_text_length = 0;
+        int             macKeySize = param.getMacKeySize();
+
+        kdf.init(kParam);
+
+        if (cipher == null)     // stream mode
+        {
+            byte[]  buf = new byte[inLen + (macKeySize / 8)];
+
+            C = new byte[inLen + mac.getMacSize()];
+            c_text_length = inLen;
+
+            kdf.generateBytes(buf, 0, buf.length);
+
+            for (int i = 0; i != inLen; i++)
+            {
+                C[i] = (byte)(in[inOff + i] ^ buf[i]);
+            }
+
+            macKey = new KeyParameter(buf, inLen, (macKeySize / 8));
+        }
+        else
+        {
+            int     cipherKeySize = ((IESWithCipherParameters)param).getCipherKeySize();
+            byte[]  buf = new byte[(cipherKeySize / 8) + (macKeySize / 8)];
+
+            cipher.init(true, new KeyParameter(buf, 0, (cipherKeySize / 8)));
+
+            c_text_length = cipher.getOutputSize(inLen);
+
+            C = new byte[c_text_length + mac.getMacSize()];
+
+            int off = cipher.processBytes(in, inOff, inLen, C, 0);
+
+            cipher.doFinal(C, off);
+
+            macKey = new KeyParameter(buf, (cipherKeySize / 8), (macKeySize / 8));
+        }
+
+        byte[]  macIV = param.getEncodingV();
+
+        mac.init(macKey);
+        mac.update(C, 0, c_text_length);
+        mac.update(macIV, 0, macIV.length);
+        //
+        // return the message and it's MAC
+        //
+        mac.doFinal(C, c_text_length);
+        return C;
+    }
+
+    public byte[] processBlock(
+        byte[]  in,
+        int     inOff,
+        int     inLen)
+        throws InvalidCipherTextException
+    {
+        agree.init(privParam);
+
+        BigInteger  z = agree.calculateAgreement(pubParam);
+
+        if (forEncryption)
+        {
+            return encryptBlock(in, inOff, inLen, z.toByteArray());
+        }
+        else
+        {
+            return decryptBlock(in, inOff, inLen, z.toByteArray());
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/engines/NullEngine.java b/libcore/security/src/main/java/org/bouncycastle/crypto/engines/NullEngine.java
new file mode 100644
index 0000000..22544ac
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/engines/NullEngine.java
@@ -0,0 +1,79 @@
+package org.bouncycastle.crypto.engines;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+
+/**
+ * The no-op engine that just copies bytes through, irrespective of whether encrypting and decrypting.
+ * Provided for the sake of completeness.
+ */
+public class NullEngine implements BlockCipher
+{
+
+    protected static final int BLOCK_SIZE = 1;
+    
+    /**
+     * Standard constructor.
+     */
+    public NullEngine()
+    {
+        super();
+    }
+
+    /* (non-Javadoc)
+     * @see org.bouncycastle.crypto.BlockCipher#init(boolean, org.bouncycastle.crypto.CipherParameters)
+     */
+    public void init(boolean forEncryption, CipherParameters params) throws IllegalArgumentException
+    {
+        // we don't mind any parameters that may come in
+    }
+
+    /* (non-Javadoc)
+     * @see org.bouncycastle.crypto.BlockCipher#getAlgorithmName()
+     */
+    public String getAlgorithmName()
+    {
+        return "Null";
+    }
+
+    /* (non-Javadoc)
+     * @see org.bouncycastle.crypto.BlockCipher#getBlockSize()
+     */
+    public int getBlockSize()
+    {
+        return BLOCK_SIZE;
+    }
+
+    /* (non-Javadoc)
+     * @see org.bouncycastle.crypto.BlockCipher#processBlock(byte[], int, byte[], int)
+     */
+    public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
+        throws DataLengthException, IllegalStateException
+    {
+            if ((inOff + BLOCK_SIZE) > in.length)
+            {
+                throw new DataLengthException("input buffer too short");
+            }
+
+            if ((outOff + BLOCK_SIZE) > out.length)
+            {
+                throw new DataLengthException("output buffer too short");
+            }
+            
+            for (int i = 0; i < BLOCK_SIZE; ++i)
+            {
+                out[outOff + i] = in[inOff + i];
+            }
+            
+            return BLOCK_SIZE;
+    }
+
+    /* (non-Javadoc)
+     * @see org.bouncycastle.crypto.BlockCipher#reset()
+     */
+    public void reset()
+    {
+        // nothing needs to be done
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/engines/RSAEngine.java b/libcore/security/src/main/java/org/bouncycastle/crypto/engines/RSAEngine.java
new file mode 100644
index 0000000..a010b01
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/engines/RSAEngine.java
@@ -0,0 +1,200 @@
+package org.bouncycastle.crypto.engines;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+
+/**
+ * this does your basic RSA algorithm.
+ */
+public class RSAEngine
+    implements AsymmetricBlockCipher
+{
+    private RSAKeyParameters        key;
+    private boolean                 forEncryption;
+    private int                     shift;
+
+    /**
+     * initialise the RSA engine.
+     *
+     * @param forEncryption true if we are encrypting, false otherwise.
+     * @param param the necessary RSA key parameters.
+     */
+    public void init(
+        boolean             forEncryption,
+        CipherParameters    param)
+    {
+        this.key = (RSAKeyParameters)param;
+        this.forEncryption = forEncryption;
+        
+        int     bitSize = key.getModulus().bitLength();
+        
+        if (bitSize % 8 == 0)    // a multiple of 8
+        {
+            this.shift = 0;
+        }
+        else
+        {
+            this.shift = (8 - (bitSize % 8));
+        }
+    }
+
+    /**
+     * Return the maximum size for an input block to this engine.
+     * For RSA this is always one byte less than the key size on
+     * encryption, and the same length as the key size on decryption.
+     *
+     * @return maximum size for an input block.
+     */
+    public int getInputBlockSize()
+    {
+        int     bitSize = key.getModulus().bitLength();
+
+        if (forEncryption)
+        {
+            return (bitSize + 7) / 8 - 1;
+        }
+        else
+        {
+            return (bitSize + 7) / 8;
+        }
+    }
+
+    /**
+     * Return the maximum size for an output block to this engine.
+     * For RSA this is always one byte less than the key size on
+     * decryption, and the same length as the key size on encryption.
+     *
+     * @return maximum size for an output block.
+     */
+    public int getOutputBlockSize()
+    {
+        int     bitSize = key.getModulus().bitLength();
+
+        if (forEncryption)
+        {
+            return (bitSize + 7) / 8;
+        }
+        else
+        {
+            return (bitSize + 7) / 8 - 1;
+        }
+    }
+
+    /**
+     * Process a single block using the basic RSA algorithm.
+     *
+     * @param in the input array.
+     * @param inOff the offset into the input buffer where the data starts.
+     * @param inLen the length of the data to be processed.
+     * @return the result of the RSA process.
+     * @exception DataLengthException the input block is too large.
+     */
+    public byte[] processBlock(
+        byte[]  in,
+        int     inOff,
+        int     inLen)
+    {
+        if (inLen > (getInputBlockSize() + 1))
+        {
+            throw new DataLengthException("input too large for RSA cipher.\n");
+        }
+        else if (inLen == (getInputBlockSize() + 1) && (in[inOff] & (0x80 >> shift)) != 0)
+        {
+            throw new DataLengthException("input too large for RSA cipher.\n");
+        }
+
+        byte[]  block;
+
+        if (inOff != 0 || inLen != in.length)
+        {
+            block = new byte[inLen];
+
+            System.arraycopy(in, inOff, block, 0, inLen);
+        }
+        else
+        {
+            block = in;
+        }
+
+        BigInteger  input = new BigInteger(1, block);
+        byte[]      output;
+
+        if (key instanceof RSAPrivateCrtKeyParameters)
+        {
+            //
+            // we have the extra factors, use the Chinese Remainder Theorem - the author
+            // wishes to express his thanks to Dirk Bonekaemper at rtsffm.com for 
+            // advice regarding the expression of this.
+            //
+            RSAPrivateCrtKeyParameters crtKey = (RSAPrivateCrtKeyParameters)key;
+
+            BigInteger p = crtKey.getP();
+            BigInteger q = crtKey.getQ();
+            BigInteger dP = crtKey.getDP();
+            BigInteger dQ = crtKey.getDQ();
+            BigInteger qInv = crtKey.getQInv();
+    
+            BigInteger mP, mQ, h, m;
+    
+            // mP = ((input mod p) ^ dP)) mod p
+            mP = (input.remainder(p)).modPow(dP, p);
+    
+            // mQ = ((input mod q) ^ dQ)) mod q
+            mQ = (input.remainder(q)).modPow(dQ, q);
+    
+            // h = qInv * (mP - mQ) mod p
+            h = mP.subtract(mQ);
+            h = h.multiply(qInv);
+            h = h.mod(p);               // mod (in Java) returns the positive residual
+    
+            // m = h * q + mQ
+            m = h.multiply(q);
+            m = m.add(mQ);
+    
+            output = m.toByteArray();
+        }
+        else
+        {
+            output = input.modPow(
+                        key.getExponent(), key.getModulus()).toByteArray();
+        }
+
+        if (forEncryption)
+        {
+            if (output[0] == 0 && output.length > getOutputBlockSize())        // have ended up with an extra zero byte, copy down.
+            {
+                byte[]  tmp = new byte[output.length - 1];
+
+                System.arraycopy(output, 1, tmp, 0, tmp.length);
+
+                return tmp;
+            }
+
+            if (output.length < getOutputBlockSize())     // have ended up with less bytes than normal, lengthen
+            {
+                byte[]  tmp = new byte[getOutputBlockSize()];
+
+                System.arraycopy(output, 0, tmp, tmp.length - output.length, output.length);
+
+                return tmp;
+            }
+        }
+        else
+        {
+            if (output[0] == 0)        // have ended up with an extra zero byte, copy down.
+            {
+                byte[]  tmp = new byte[output.length - 1];
+
+                System.arraycopy(output, 1, tmp, 0, tmp.length);
+
+                return tmp;
+            }
+        }
+        return output;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/generators/BaseKDFBytesGenerator.java b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/BaseKDFBytesGenerator.java
new file mode 100644
index 0000000..268ae9b
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/BaseKDFBytesGenerator.java
@@ -0,0 +1,142 @@
+package org.bouncycastle.crypto.generators;
+
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.DerivationFunction;
+import org.bouncycastle.crypto.DerivationParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.params.ISO18033KDFParameters;
+import org.bouncycastle.crypto.params.KDFParameters;
+
+/**
+ * Basic KDF generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+ * <br>
+ * This implementation is based on ISO 18033/P1363a.
+ */
+public class BaseKDFBytesGenerator
+    implements DerivationFunction
+{
+    private int     counterStart;
+    private Digest  digest;
+    private byte[]  shared;
+    private byte[]  iv;
+
+    /**
+     * Construct a KDF Parameters generator.
+     * <p>
+     * @param counterStart value of counter.
+     * @param digest the digest to be used as the source of derived keys.
+     */
+    protected BaseKDFBytesGenerator(
+        int     counterStart,
+        Digest  digest)
+    {
+        this.counterStart = counterStart;
+        this.digest = digest;
+    }
+
+    public void init(
+        DerivationParameters    param)
+    {
+        if (param instanceof KDFParameters)
+        {
+            KDFParameters   p = (KDFParameters)param;
+
+            shared = p.getSharedSecret();
+            iv = p.getIV();
+        }
+        else if (param instanceof ISO18033KDFParameters)
+        {
+            ISO18033KDFParameters p = (ISO18033KDFParameters)param;
+            
+            shared = p.getSeed();
+            iv = null;
+        }
+        else
+        {
+            throw new IllegalArgumentException("KDF parameters required for KDF2Generator");
+        }
+    }
+
+    /**
+     * return the underlying digest.
+     */
+    public Digest getDigest()
+    {
+        return digest;
+    }
+
+    /**
+     * fill len bytes of the output buffer with bytes generated from
+     * the derivation function.
+     *
+     * @throws IllegalArgumentException if the size of the request will cause an overflow.
+     * @throws DataLengthException if the out buffer is too small.
+     */
+    public int generateBytes(
+        byte[]  out,
+        int     outOff,
+        int     len)
+        throws DataLengthException, IllegalArgumentException
+    {
+        if ((out.length - len) < outOff)
+        {
+            throw new DataLengthException("output buffer too small");
+        }
+
+        long    oBytes = len;
+        int     outLen = digest.getDigestSize(); 
+
+        //
+        // this is at odds with the standard implementation, the
+        // maximum value should be hBits * (2^32 - 1) where hBits
+        // is the digest output size in bits. We can't have an
+        // array with a long index at the moment...
+        //
+        if (oBytes > ((2L << 32) - 1))
+        {
+            throw new IllegalArgumentException("Output length too large");
+        }
+
+        int cThreshold = (int)((oBytes + outLen - 1) / outLen);
+
+        byte[] dig = null;
+
+        dig = new byte[digest.getDigestSize()];
+
+        int counter = counterStart;
+        
+        for (int i = 0; i < cThreshold; i++)
+        {
+            digest.update(shared, 0, shared.length);
+
+            digest.update((byte)(counter >> 24));
+            digest.update((byte)(counter >> 16));
+            digest.update((byte)(counter >> 8));
+            digest.update((byte)counter);
+            
+            if (iv != null)
+            {
+                digest.update(iv, 0, iv.length);
+            }
+
+            digest.doFinal(dig, 0);
+
+            if (len > outLen)
+            {
+                System.arraycopy(dig, 0, out, outOff, outLen);
+                outOff += outLen;
+                len -= outLen;
+            }
+            else
+            {
+                System.arraycopy(dig, 0, out, outOff, len);
+            }
+            
+            counter++;
+        }
+    
+        digest.reset();
+
+        return len;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DESKeyGenerator.java b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DESKeyGenerator.java
new file mode 100644
index 0000000..bb3f6d0
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DESKeyGenerator.java
@@ -0,0 +1,23 @@
+package org.bouncycastle.crypto.generators;
+
+import org.bouncycastle.crypto.CipherKeyGenerator;
+import org.bouncycastle.crypto.params.DESParameters;
+
+public class DESKeyGenerator
+    extends CipherKeyGenerator
+{
+    public byte[] generateKey()
+    {
+        byte[]  newKey = new byte[DESParameters.DES_KEY_LENGTH];
+
+        do
+        {
+            random.nextBytes(newKey);
+
+            DESParameters.setOddParity(newKey);
+        }
+        while (DESParameters.isWeakKey(newKey, 0));
+
+        return newKey;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DESedeKeyGenerator.java b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DESedeKeyGenerator.java
new file mode 100644
index 0000000..101dc37
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DESedeKeyGenerator.java
@@ -0,0 +1,55 @@
+package org.bouncycastle.crypto.generators;
+
+import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.crypto.params.DESedeParameters;
+
+public class DESedeKeyGenerator
+    extends DESKeyGenerator
+{
+    /**
+     * initialise the key generator - if strength is set to zero
+     * the key generated will be 192 bits in size, otherwise
+     * strength can be 128 or 192 (or 112 or 168 if you don't count
+     * parity bits), depending on whether you wish to do 2-key or 3-key
+     * triple DES.
+     *
+     * @param param the parameters to be used for key generation
+     */
+    public void init(
+        KeyGenerationParameters param)
+    {
+        super.init(param);
+
+        if (strength == 0 || strength == (168 / 8))
+        {
+            strength = DESedeParameters.DES_EDE_KEY_LENGTH;
+        }
+        else if (strength == (112 / 8))
+        {
+            strength = 2 * DESedeParameters.DES_KEY_LENGTH;
+        }
+        else if (strength != DESedeParameters.DES_EDE_KEY_LENGTH
+                && strength != (2 * DESedeParameters.DES_KEY_LENGTH))
+        {
+            throw new IllegalArgumentException("DESede key must be "
+                + (DESedeParameters.DES_EDE_KEY_LENGTH * 8) + " or "
+                + (2 * 8 * DESedeParameters.DES_KEY_LENGTH)
+                + " bits long.");
+        }
+    }
+
+    public byte[] generateKey()
+    {
+        byte[]  newKey = new byte[strength];
+
+        do
+        {
+            random.nextBytes(newKey);
+
+            DESedeParameters.setOddParity(newKey);
+        }
+        while (DESedeParameters.isWeakKey(newKey, 0, newKey.length));
+
+        return newKey;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DHBasicKeyPairGenerator.java b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DHBasicKeyPairGenerator.java
new file mode 100644
index 0000000..213c052
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DHBasicKeyPairGenerator.java
@@ -0,0 +1,44 @@
+package org.bouncycastle.crypto.generators;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.crypto.params.DHKeyGenerationParameters;
+import org.bouncycastle.crypto.params.DHParameters;
+import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import org.bouncycastle.crypto.params.DHPublicKeyParameters;
+
+/**
+ * a basic Diffie-Helman key pair generator.
+ *
+ * This generates keys consistent for use with the basic algorithm for
+ * Diffie-Helman.
+ */
+public class DHBasicKeyPairGenerator
+    implements AsymmetricCipherKeyPairGenerator
+{
+    private DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.INSTANCE;
+    private DHKeyGenerationParameters param;
+
+    public void init(
+        KeyGenerationParameters param)
+    {
+        this.param = (DHKeyGenerationParameters)param;
+    }
+
+    public AsymmetricCipherKeyPair generateKeyPair()
+    {
+        BigInteger      p, x, y;
+        DHParameters    dhParams = param.getParameters();
+
+        p = dhParams.getP();
+        x = helper.calculatePrivate(p, param.getRandom(), dhParams.getJ()); 
+        y = helper.calculatePublic(p, dhParams.getG(), x);
+
+        return new AsymmetricCipherKeyPair(
+                new DHPublicKeyParameters(y, dhParams),
+                new DHPrivateKeyParameters(x, dhParams));
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java
new file mode 100644
index 0000000..abbda43
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java
@@ -0,0 +1,68 @@
+package org.bouncycastle.crypto.generators;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+class DHKeyGeneratorHelper
+{
+    private static final int MAX_ITERATIONS = 1000;
+
+    static final DHKeyGeneratorHelper INSTANCE = new DHKeyGeneratorHelper();
+    
+    private static BigInteger ZERO = BigInteger.valueOf(0);
+    private static BigInteger TWO = BigInteger.valueOf(2);
+    
+    private DHKeyGeneratorHelper()
+    {
+    }
+    
+    BigInteger calculatePrivate(BigInteger p, SecureRandom random, int limit)
+    {
+        //
+        // calculate the private key
+        //
+        BigInteger pSub2 = p.subtract(TWO);
+        BigInteger x;
+        
+        if (limit == 0)
+        {
+            x = createInRange(pSub2, random);
+        }
+        else
+        {
+            do
+            {
+                x = new BigInteger(limit, random);
+            }
+            while (x.equals(ZERO));
+        }
+        
+        return x;
+    }
+
+    private BigInteger createInRange(BigInteger max, SecureRandom random)
+    {
+        BigInteger x;
+        int maxLength = max.bitLength();
+        int count = 0;
+        
+        do
+        {
+            x = new BigInteger(maxLength, random);
+            count++;
+        }
+        while ((x.equals(ZERO) || x.compareTo(max) > 0) && count != MAX_ITERATIONS);
+        
+        if (count == MAX_ITERATIONS)  // fall back to a faster (restricted) method
+        {
+            return new BigInteger(maxLength - 1, random).setBit(0);
+        }
+        
+        return x;
+    }
+    
+    BigInteger calculatePublic(BigInteger p, BigInteger g, BigInteger x)
+    {
+        return g.modPow(x, p);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DHKeyPairGenerator.java b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DHKeyPairGenerator.java
new file mode 100644
index 0000000..8c734cd
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DHKeyPairGenerator.java
@@ -0,0 +1,45 @@
+package org.bouncycastle.crypto.generators;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.crypto.params.DHKeyGenerationParameters;
+import org.bouncycastle.crypto.params.DHParameters;
+import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import org.bouncycastle.crypto.params.DHPublicKeyParameters;
+
+/**
+ * a Diffie-Helman key pair generator.
+ *
+ * This generates keys consistent for use in the MTI/A0 key agreement protocol
+ * as described in "Handbook of Applied Cryptography", Pages 516-519.
+ */
+public class DHKeyPairGenerator
+    implements AsymmetricCipherKeyPairGenerator
+{
+    private DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.INSTANCE;
+    
+    private DHKeyGenerationParameters param;
+
+    public void init(
+        KeyGenerationParameters param)
+    {
+        this.param = (DHKeyGenerationParameters)param;
+    }
+
+    public AsymmetricCipherKeyPair generateKeyPair()
+    {
+        BigInteger      p, x, y;
+        DHParameters    dhParams = param.getParameters();
+        
+        p = dhParams.getP();
+        x = helper.calculatePrivate(p, param.getRandom(), dhParams.getJ()); 
+        y = helper.calculatePublic(p, dhParams.getG(), x);
+
+        return new AsymmetricCipherKeyPair(
+                new DHPublicKeyParameters(y, dhParams),
+                new DHPrivateKeyParameters(x, dhParams));
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DHParametersGenerator.java b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DHParametersGenerator.java
new file mode 100644
index 0000000..f3dff34
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DHParametersGenerator.java
@@ -0,0 +1,81 @@
+package org.bouncycastle.crypto.generators;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.params.DHParameters;
+
+public class DHParametersGenerator
+{
+    private int             size;
+    private int             certainty;
+    private SecureRandom    random;
+
+    private static BigInteger ONE = BigInteger.valueOf(1);
+    private static BigInteger TWO = BigInteger.valueOf(2);
+
+    /**
+     * Initialise the parameters generator.
+     * 
+     * @param size bit length for the prime p
+     * @param certainty level of certainty for the prime number tests
+     * @param random  a source of randomness
+     */
+    public void init(
+        int             size,
+        int             certainty,
+        SecureRandom    random)
+    {
+        this.size = size;
+        this.certainty = certainty;
+        this.random = random;
+    }
+
+    /**
+     * which generates the p and g values from the given parameters,
+     * returning the DHParameters object.
+     * <p>
+     * Note: can take a while...
+     */
+    public DHParameters generateParameters()
+    {
+        BigInteger      g, p, q;
+        int             qLength = size - 1;
+
+        //
+        // find a safe prime p where p = 2*q + 1, where p and q are prime.
+        //
+        for (;;)
+        {
+            q = new BigInteger(qLength, certainty, random);
+            p = q.multiply(TWO).add(ONE);
+            if (p.isProbablePrime(certainty))
+            {
+                break;
+            }
+        }
+
+        //
+        // calculate the generator g - the advantage of using the 2q+1 
+        // approach is that we know the prime factorisation of (p - 1)...
+        //
+        for (;;)
+        {
+            g = new BigInteger(qLength, random);
+
+            if (g.modPow(TWO, p).equals(ONE))
+            {
+                continue;
+            }
+
+            if (g.modPow(q, p).equals(ONE))
+            {
+                continue;
+            }
+
+            break;
+        }
+
+        return new DHParameters(p, g, q, 2);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DSAKeyPairGenerator.java b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DSAKeyPairGenerator.java
new file mode 100644
index 0000000..e1a9655
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DSAKeyPairGenerator.java
@@ -0,0 +1,58 @@
+package org.bouncycastle.crypto.generators;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.crypto.params.DSAKeyGenerationParameters;
+import org.bouncycastle.crypto.params.DSAParameters;
+import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
+
+/**
+ * a DSA key pair generator.
+ *
+ * This generates DSA keys in line with the method described 
+ * in FIPS 186-2.
+ */
+public class DSAKeyPairGenerator
+    implements AsymmetricCipherKeyPairGenerator
+{
+    private static BigInteger ZERO = BigInteger.valueOf(0);
+
+    private DSAKeyGenerationParameters param;
+
+    public void init(
+        KeyGenerationParameters param)
+    {
+        this.param = (DSAKeyGenerationParameters)param;
+    }
+
+    public AsymmetricCipherKeyPair generateKeyPair()
+    {
+        BigInteger      p, q, g, x, y;
+        DSAParameters   dsaParams = param.getParameters();
+        SecureRandom    random = param.getRandom();
+
+        q = dsaParams.getQ();
+        p = dsaParams.getP();
+        g = dsaParams.getG();
+
+        do
+        {
+            x = new BigInteger(160, random);
+        }
+        while (x.equals(ZERO)  || x.compareTo(q) >= 0);
+
+        //
+        // calculate the public key.
+        //
+        y = g.modPow(x, p);
+
+        return new AsymmetricCipherKeyPair(
+                new DSAPublicKeyParameters(y, dsaParams),
+                new DSAPrivateKeyParameters(x, dsaParams));
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
new file mode 100644
index 0000000..4996b1e
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
@@ -0,0 +1,178 @@
+package org.bouncycastle.crypto.generators;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.params.DSAParameters;
+import org.bouncycastle.crypto.params.DSAValidationParameters;
+
+/**
+ * generate suitable parameters for DSA, in line with FIPS 186-2.
+ */
+public class DSAParametersGenerator
+{
+    private int             size;
+    private int             certainty;
+    private SecureRandom    random;
+
+    private static BigInteger ONE = BigInteger.valueOf(1);
+    private static BigInteger TWO = BigInteger.valueOf(2);
+
+    /**
+     * initialise the key generator.
+     *
+     * @param size size of the key (range 2^512 -> 2^1024 - 64 bit increments)
+     * @param certainty measure of robustness of prime (for FIPS 186-2 compliance this should be at least 80).
+     * @param random random byte source.
+     */
+    public void init(
+        int             size,
+        int             certainty,
+        SecureRandom    random)
+    {
+        this.size = size;
+        this.certainty = certainty;
+        this.random = random;
+    }
+
+    /**
+     * add value to b, returning the result in a. The a value is treated
+     * as a BigInteger of length (a.length * 8) bits. The result is
+     * modulo 2^a.length in case of overflow.
+     */
+    private void add(
+        byte[]  a,
+        byte[]  b,
+        int     value)
+    {
+        int     x = (b[b.length - 1] & 0xff) + value;
+
+        a[b.length - 1] = (byte)x;
+        x >>>= 8;
+
+        for (int i = b.length - 2; i >= 0; i--)
+        {
+            x += (b[i] & 0xff);
+            a[i] = (byte)x;
+            x >>>= 8;
+        }
+    }
+
+    /**
+     * which generates the p and g values from the given parameters,
+     * returning the DSAParameters object.
+     * <p>
+     * Note: can take a while...
+     */
+    public DSAParameters generateParameters()
+    {
+        byte[]          seed = new byte[20];
+        byte[]          part1 = new byte[20];
+        byte[]          part2 = new byte[20];
+        byte[]          u = new byte[20];
+        SHA1Digest      sha1 = new SHA1Digest();
+        int             n = (size - 1) / 160;
+        byte[]          w = new byte[size / 8];
+
+        BigInteger      q = null, p = null, g = null;
+        int             counter = 0;
+        boolean         primesFound = false;
+
+        while (!primesFound)
+        {
+            do
+            {
+                random.nextBytes(seed);
+
+                sha1.update(seed, 0, seed.length);
+
+                sha1.doFinal(part1, 0);
+
+                System.arraycopy(seed, 0, part2, 0, seed.length);
+
+                add(part2, seed, 1);
+
+                sha1.update(part2, 0, part2.length);
+
+                sha1.doFinal(part2, 0);
+
+                for (int i = 0; i != u.length; i++)
+                {
+                    u[i] = (byte)(part1[i] ^ part2[i]);
+                }
+
+                u[0] |= (byte)0x80;
+                u[19] |= (byte)0x01;
+
+                q = new BigInteger(1, u);
+            }
+            while (!q.isProbablePrime(certainty));
+
+            counter = 0;
+
+            int offset = 2;
+
+            while (counter < 4096)
+            {
+                for (int k = 0; k < n; k++)
+                {
+                    add(part1, seed, offset + k);
+                    sha1.update(part1, 0, part1.length);
+                    sha1.doFinal(part1, 0);
+                    System.arraycopy(part1, 0, w, w.length - (k + 1) * part1.length, part1.length);
+                }
+
+                add(part1, seed, offset + n);
+                sha1.update(part1, 0, part1.length);
+                sha1.doFinal(part1, 0);
+                System.arraycopy(part1, part1.length - ((w.length - (n) * part1.length)), w, 0, w.length - n * part1.length);
+
+                w[0] |= (byte)0x80;
+
+                BigInteger  x = new BigInteger(1, w);
+
+                BigInteger  c = x.mod(q.multiply(TWO));
+
+                p = x.subtract(c.subtract(ONE));
+
+                if (p.testBit(size - 1))
+                {
+                    if (p.isProbablePrime(certainty))
+                    {
+                        primesFound = true;
+                        break;
+                    }
+                }
+
+                counter += 1;
+                offset += n + 1;
+            }
+        }
+
+        //
+        // calculate the generator g
+        //
+        BigInteger  pMinusOneOverQ = p.subtract(ONE).divide(q);
+
+        for (;;)
+        {
+            BigInteger h = new BigInteger(size, random);
+            
+            if (h.compareTo(ONE) <= 0 || h.compareTo(p.subtract(ONE)) >= 0)
+            {
+                continue;
+            }
+
+            g = h.modPow(pMinusOneOverQ, p);
+            if (g.compareTo(ONE) <= 0)
+            {
+                continue;
+            }
+
+            break;
+        }
+
+        return new DSAParameters(p, q, g, new DSAValidationParameters(seed, counter));
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/generators/KDF1BytesGenerator.java b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/KDF1BytesGenerator.java
new file mode 100644
index 0000000..7789b7b
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/KDF1BytesGenerator.java
@@ -0,0 +1,23 @@
+package org.bouncycastle.crypto.generators;
+
+import org.bouncycastle.crypto.Digest;
+
+/**
+ * KDF1 generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+ * <br>
+ * This implementation is based on ISO 18033/IEEE P1363a.
+ */
+public class KDF1BytesGenerator
+    extends BaseKDFBytesGenerator
+{
+    /**
+     * Construct a KDF1 byte generator.
+     * <p>
+     * @param digest the digest to be used as the source of derived keys.
+     */
+    public KDF1BytesGenerator(
+        Digest  digest)
+    {
+        super(0, digest);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/generators/KDF2BytesGenerator.java b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/KDF2BytesGenerator.java
new file mode 100644
index 0000000..cab05ac
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/KDF2BytesGenerator.java
@@ -0,0 +1,24 @@
+package org.bouncycastle.crypto.generators;
+
+import org.bouncycastle.crypto.Digest;
+
+/**
+ * KFD2 generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+ * <br>
+ * This implementation is based on IEEE P1363/ISO 18033.
+ */
+public class KDF2BytesGenerator
+    extends BaseKDFBytesGenerator
+{
+    /**
+     * Construct a KDF2 bytes generator. Generates key material
+     * according to IEEE P1363 or ISO 18033 depending on the initialisation.
+     * <p>
+     * @param digest the digest to be used as the source of derived keys.
+     */
+    public KDF2BytesGenerator(
+        Digest  digest)
+    {
+        super(1, digest);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/generators/MGF1BytesGenerator.java b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/MGF1BytesGenerator.java
new file mode 100644
index 0000000..e93c0d7
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/MGF1BytesGenerator.java
@@ -0,0 +1,114 @@
+package org.bouncycastle.crypto.generators;
+
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.DerivationFunction;
+import org.bouncycastle.crypto.DerivationParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.params.MGFParameters;
+
+/**
+ * Generator for MGF1 as defined in PKCS 1v2
+ */
+public class MGF1BytesGenerator
+    implements DerivationFunction
+{
+    private Digest  digest;
+    private byte[]  seed;
+    private int     hLen;
+
+    /**
+     * @param digest the digest to be used as the source of generated bytes
+     */
+    public MGF1BytesGenerator(
+        Digest  digest)
+    {
+        this.digest = digest;
+        this.hLen = digest.getDigestSize();
+    }
+
+    public void init(
+        DerivationParameters    param)
+    {
+        if (!(param instanceof MGFParameters))
+        {
+            throw new IllegalArgumentException("MGF parameters required for MGF1Generator");
+        }
+
+        MGFParameters   p = (MGFParameters)param;
+
+        seed = p.getSeed();
+    }
+
+    /**
+     * return the underlying digest.
+     */
+    public Digest getDigest()
+    {
+        return digest;
+    }
+
+    /**
+     * int to octet string.
+     */
+    private void ItoOSP(
+        int     i,
+        byte[]  sp)
+    {
+        sp[0] = (byte)(i >>> 24);
+        sp[1] = (byte)(i >>> 16);
+        sp[2] = (byte)(i >>> 8);
+        sp[3] = (byte)(i >>> 0);
+    }
+
+    /**
+     * fill len bytes of the output buffer with bytes generated from
+     * the derivation function.
+     *
+     * @throws DataLengthException if the out buffer is too small.
+     */
+    public int generateBytes(
+        byte[]  out,
+        int     outOff,
+        int     len)
+        throws DataLengthException, IllegalArgumentException
+    {
+        if ((out.length - len) < outOff)
+        {
+            throw new DataLengthException("output buffer too small");
+        }
+        
+        byte[]  hashBuf = new byte[hLen];
+        byte[]  C = new byte[4];
+        int     counter = 0;
+
+        digest.reset();
+
+        if (len > hLen)
+        {
+            do
+            {
+                ItoOSP(counter, C);
+    
+                digest.update(seed, 0, seed.length);
+                digest.update(C, 0, C.length);
+                digest.doFinal(hashBuf, 0);
+    
+                System.arraycopy(hashBuf, 0, out, outOff + counter * hLen, hLen);
+            }
+            while (++counter < (len / hLen));
+        }
+
+        if ((counter * hLen) < len)
+        {
+            ItoOSP(counter, C);
+
+            digest.update(seed, 0, seed.length);
+            digest.update(C, 0, C.length);
+            digest.doFinal(hashBuf, 0);
+
+            System.arraycopy(hashBuf, 0, out, outOff + counter * hLen, len - (counter * hLen));
+        }
+
+        return len;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java
new file mode 100644
index 0000000..8a4d28a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java
@@ -0,0 +1,131 @@
+package org.bouncycastle.crypto.generators;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.PBEParametersGenerator;
+import org.bouncycastle.crypto.digests.MD5Digest;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * Generator for PBE derived keys and ivs as usd by OpenSSL.
+ * <p>
+ * The scheme is a simple extension of PKCS 5 V2.0 Scheme 1 using MD5 with an
+ * iteration count of 1.
+ * <p>
+ */
+public class OpenSSLPBEParametersGenerator
+    extends PBEParametersGenerator
+{
+    private Digest  digest = new MD5Digest();
+
+    /**
+     * Construct a OpenSSL Parameters generator. 
+     */
+    public OpenSSLPBEParametersGenerator()
+    {
+    }
+
+    /**
+     * Initialise - note the iteration count for this algorithm is fixed at 1.
+     * 
+     * @param password password to use.
+     * @param salt salt to use.
+     */
+    public void init(
+       byte[] password,
+       byte[] salt)
+    {
+        super.init(password, salt, 1);
+    }
+    
+    /**
+     * the derived key function, the ith hash of the password and the salt.
+     */
+    private byte[] generateDerivedKey(
+        int bytesNeeded)
+    {
+        byte[]  buf = new byte[digest.getDigestSize()];
+        byte[]  key = new byte[bytesNeeded];
+        int     offset = 0;
+        
+        for (;;)
+        {
+            digest.update(password, 0, password.length);
+            digest.update(salt, 0, salt.length);
+
+            digest.doFinal(buf, 0);
+            
+            int len = (bytesNeeded > buf.length) ? buf.length : bytesNeeded;
+            System.arraycopy(buf, 0, key, offset, len);
+            offset += len;
+
+            // check if we need any more
+            bytesNeeded -= len;
+            if (bytesNeeded == 0)
+            {
+                break;
+            }
+
+            // do another round
+            digest.reset();
+            digest.update(buf, 0, buf.length);
+        }
+        
+        return key;
+    }
+
+    /**
+     * Generate a key parameter derived from the password, salt, and iteration
+     * count we are currently initialised with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @return a KeyParameter object.
+     * @exception IllegalArgumentException if the key length larger than the base hash size.
+     */
+    public CipherParameters generateDerivedParameters(
+        int keySize)
+    {
+        keySize = keySize / 8;
+
+        byte[]  dKey = generateDerivedKey(keySize);
+
+        return new KeyParameter(dKey, 0, keySize);
+    }
+
+    /**
+     * Generate a key with initialisation vector parameter derived from
+     * the password, salt, and iteration count we are currently initialised
+     * with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @param ivSize the size of the iv we want (in bits)
+     * @return a ParametersWithIV object.
+     * @exception IllegalArgumentException if keySize + ivSize is larger than the base hash size.
+     */
+    public CipherParameters generateDerivedParameters(
+        int     keySize,
+        int     ivSize)
+    {
+        keySize = keySize / 8;
+        ivSize = ivSize / 8;
+
+        byte[]  dKey = generateDerivedKey(keySize + ivSize);
+
+        return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
+    }
+
+    /**
+     * Generate a key parameter for use with a MAC derived from the password,
+     * salt, and iteration count we are currently initialised with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @return a KeyParameter object.
+     * @exception IllegalArgumentException if the key length larger than the base hash size.
+     */
+    public CipherParameters generateDerivedMacParameters(
+        int keySize)
+    {
+        return generateDerivedParameters(keySize);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/generators/PKCS12ParametersGenerator.java b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/PKCS12ParametersGenerator.java
new file mode 100644
index 0000000..bf2f368
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/PKCS12ParametersGenerator.java
@@ -0,0 +1,221 @@
+package org.bouncycastle.crypto.generators;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.ExtendedDigest;
+import org.bouncycastle.crypto.PBEParametersGenerator;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * Generator for PBE derived keys and ivs as defined by PKCS 12 V1.0.
+ * <p>
+ * The document this implementation is based on can be found at
+ * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-12/index.html>
+ * RSA's PKCS12 Page</a>
+ */
+public class PKCS12ParametersGenerator
+    extends PBEParametersGenerator
+{
+    public static final int KEY_MATERIAL = 1;
+    public static final int IV_MATERIAL  = 2;
+    public static final int MAC_MATERIAL = 3;
+
+    private Digest digest;
+
+    private int     u;
+    private int     v;
+
+    /**
+     * Construct a PKCS 12 Parameters generator. This constructor will
+     * accept any digest which also implements ExtendedDigest.
+     *
+     * @param digest the digest to be used as the source of derived keys.
+     * @exception IllegalArgumentException if an unknown digest is passed in.
+     */
+    public PKCS12ParametersGenerator(
+        Digest  digest)
+    {
+        this.digest = digest;
+        if (digest instanceof ExtendedDigest)
+        {
+            u = digest.getDigestSize();
+            v = ((ExtendedDigest)digest).getByteLength();
+        }
+        else
+        {
+            throw new IllegalArgumentException("Digest " + digest.getAlgorithmName() + " unsupported");
+        }
+    }
+
+    /**
+     * add a + b + 1, returning the result in a. The a value is treated
+     * as a BigInteger of length (b.length * 8) bits. The result is 
+     * modulo 2^b.length in case of overflow.
+     */
+    private void adjust(
+        byte[]  a,
+        int     aOff,
+        byte[]  b)
+    {
+        int  x = (b[b.length - 1] & 0xff) + (a[aOff + b.length - 1] & 0xff) + 1;
+
+        a[aOff + b.length - 1] = (byte)x;
+        x >>>= 8;
+
+        for (int i = b.length - 2; i >= 0; i--)
+        {
+            x += (b[i] & 0xff) + (a[aOff + i] & 0xff);
+            a[aOff + i] = (byte)x;
+            x >>>= 8;
+        }
+    }
+
+    /**
+     * generation of a derived key ala PKCS12 V1.0.
+     */
+    private byte[] generateDerivedKey(
+        int idByte,
+        int n)
+    {
+        byte[]  D = new byte[v];
+        byte[]  dKey = new byte[n];
+
+        for (int i = 0; i != D.length; i++)
+        {
+            D[i] = (byte)idByte;
+        }
+
+        byte[]  S;
+
+        if ((salt != null) && (salt.length != 0))
+        {
+            S = new byte[v * ((salt.length + v - 1) / v)];
+
+            for (int i = 0; i != S.length; i++)
+            {
+                S[i] = salt[i % salt.length];
+            }
+        }
+        else
+        {
+            S = new byte[0];
+        }
+
+        byte[]  P;
+
+        if ((password != null) && (password.length != 0))
+        {
+            P = new byte[v * ((password.length + v - 1) / v)];
+
+            for (int i = 0; i != P.length; i++)
+            {
+                P[i] = password[i % password.length];
+            }
+        }
+        else
+        {
+            P = new byte[0];
+        }
+
+        byte[]  I = new byte[S.length + P.length];
+
+        System.arraycopy(S, 0, I, 0, S.length);
+        System.arraycopy(P, 0, I, S.length, P.length);
+
+        byte[]  B = new byte[v];
+        int     c = (n + u - 1) / u;
+
+        for (int i = 1; i <= c; i++)
+        {
+            byte[]  A = new byte[u];
+
+            digest.update(D, 0, D.length);
+            digest.update(I, 0, I.length);
+            digest.doFinal(A, 0);
+            for (int j = 1; j != iterationCount; j++)
+            {
+                digest.update(A, 0, A.length);
+                digest.doFinal(A, 0);
+            }
+
+            for (int j = 0; j != B.length; j++)
+            {
+                B[j] = A[j % A.length];
+            }
+
+            for (int j = 0; j != I.length / v; j++)
+            {
+                adjust(I, j * v, B);
+            }
+
+            if (i == c)
+            {
+                System.arraycopy(A, 0, dKey, (i - 1) * u, dKey.length - ((i - 1) * u));
+            }
+            else
+            {
+                System.arraycopy(A, 0, dKey, (i - 1) * u, A.length);
+            }
+        }
+
+        return dKey;
+    }
+
+    /**
+     * Generate a key parameter derived from the password, salt, and iteration
+     * count we are currently initialised with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @return a KeyParameter object.
+     */
+    public CipherParameters generateDerivedParameters(
+        int keySize)
+    {
+        keySize = keySize / 8;
+
+        byte[]  dKey = generateDerivedKey(KEY_MATERIAL, keySize);
+
+        return new KeyParameter(dKey, 0, keySize);
+    }
+
+    /**
+     * Generate a key with initialisation vector parameter derived from
+     * the password, salt, and iteration count we are currently initialised
+     * with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @param ivSize the size of the iv we want (in bits)
+     * @return a ParametersWithIV object.
+     */
+    public CipherParameters generateDerivedParameters(
+        int     keySize,
+        int     ivSize)
+    {
+        keySize = keySize / 8;
+        ivSize = ivSize / 8;
+
+        byte[]  dKey = generateDerivedKey(KEY_MATERIAL, keySize);
+
+        byte[]  iv = generateDerivedKey(IV_MATERIAL, ivSize);
+
+        return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), iv, 0, ivSize);
+    }
+
+    /**
+     * Generate a key parameter for use with a MAC derived from the password,
+     * salt, and iteration count we are currently initialised with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @return a KeyParameter object.
+     */
+    public CipherParameters generateDerivedMacParameters(
+        int keySize)
+    {
+        keySize = keySize / 8;
+
+        byte[]  dKey = generateDerivedKey(MAC_MATERIAL, keySize);
+
+        return new KeyParameter(dKey, 0, keySize);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/generators/PKCS5S1ParametersGenerator.java b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/PKCS5S1ParametersGenerator.java
new file mode 100644
index 0000000..1c62ecc
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/PKCS5S1ParametersGenerator.java
@@ -0,0 +1,119 @@
+package org.bouncycastle.crypto.generators;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.PBEParametersGenerator;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * Generator for PBE derived keys and ivs as defined by PKCS 5 V2.0 Scheme 1.
+ * Note this generator is limited to the size of the hash produced by the
+ * digest used to drive it.
+ * <p>
+ * The document this implementation is based on can be found at
+ * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html>
+ * RSA's PKCS5 Page</a>
+ */
+public class PKCS5S1ParametersGenerator
+    extends PBEParametersGenerator
+{
+    private Digest  digest;
+
+    /**
+     * Construct a PKCS 5 Scheme 1 Parameters generator. 
+     *
+     * @param digest the digest to be used as the source of derived keys.
+     */
+    public PKCS5S1ParametersGenerator(
+        Digest  digest)
+    {
+        this.digest = digest;
+    }
+
+    /**
+     * the derived key function, the ith hash of the password and the salt.
+     */
+    private byte[] generateDerivedKey()
+    {
+        byte[] digestBytes = new byte[digest.getDigestSize()];
+
+        digest.update(password, 0, password.length);
+        digest.update(salt, 0, salt.length);
+
+        digest.doFinal(digestBytes, 0);
+        for (int i = 1; i < iterationCount; i++)
+        {
+            digest.update(digestBytes, 0, digestBytes.length);
+            digest.doFinal(digestBytes, 0);
+        }
+
+        return digestBytes;
+    }
+
+    /**
+     * Generate a key parameter derived from the password, salt, and iteration
+     * count we are currently initialised with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @return a KeyParameter object.
+     * @exception IllegalArgumentException if the key length larger than the base hash size.
+     */
+    public CipherParameters generateDerivedParameters(
+        int keySize)
+    {
+        keySize = keySize / 8;
+
+        if (keySize > digest.getDigestSize())
+        {
+            throw new IllegalArgumentException(
+                   "Can't generate a derived key " + keySize + " bytes long.");
+        }
+
+        byte[]  dKey = generateDerivedKey();
+
+        return new KeyParameter(dKey, 0, keySize);
+    }
+
+    /**
+     * Generate a key with initialisation vector parameter derived from
+     * the password, salt, and iteration count we are currently initialised
+     * with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @param ivSize the size of the iv we want (in bits)
+     * @return a ParametersWithIV object.
+     * @exception IllegalArgumentException if keySize + ivSize is larger than the base hash size.
+     */
+    public CipherParameters generateDerivedParameters(
+        int     keySize,
+        int     ivSize)
+    {
+        keySize = keySize / 8;
+        ivSize = ivSize / 8;
+
+        if ((keySize + ivSize) > digest.getDigestSize())
+        {
+            throw new IllegalArgumentException(
+                   "Can't generate a derived key " + (keySize + ivSize) + " bytes long.");
+        }
+
+        byte[]  dKey = generateDerivedKey();
+
+        return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
+    }
+
+    /**
+     * Generate a key parameter for use with a MAC derived from the password,
+     * salt, and iteration count we are currently initialised with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @return a KeyParameter object.
+     * @exception IllegalArgumentException if the key length larger than the base hash size.
+     */
+    public CipherParameters generateDerivedMacParameters(
+        int keySize)
+    {
+        return generateDerivedParameters(keySize);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java
new file mode 100644
index 0000000..9b4972d
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java
@@ -0,0 +1,151 @@
+package org.bouncycastle.crypto.generators;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.PBEParametersGenerator;
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * Generator for PBE derived keys and ivs as defined by PKCS 5 V2.0 Scheme 2.
+ * This generator uses a SHA-1 HMac as the calculation function.
+ * <p>
+ * The document this implementation is based on can be found at
+ * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html>
+ * RSA's PKCS5 Page</a>
+ */
+public class PKCS5S2ParametersGenerator
+    extends PBEParametersGenerator
+{
+    private Mac    hMac = new HMac(new SHA1Digest());
+
+    /**
+     * construct a PKCS5 Scheme 2 Parameters generator.
+     */
+    public PKCS5S2ParametersGenerator()
+    {
+    }
+
+    private void F(
+        byte[]  P,
+        byte[]  S,
+        int     c,
+        byte[]  iBuf,
+        byte[]  out,
+        int     outOff)
+    {
+        byte[]              state = new byte[hMac.getMacSize()];
+        CipherParameters    param = new KeyParameter(P);
+
+        hMac.init(param);
+
+        if (S != null)
+        {
+            hMac.update(S, 0, S.length);
+        }
+
+        hMac.update(iBuf, 0, iBuf.length);
+
+        hMac.doFinal(state, 0);
+
+        System.arraycopy(state, 0, out, outOff, state.length);
+
+        if (c == 0)
+        {
+            throw new IllegalArgumentException("iteration count must be at least 1.");
+        }
+        
+        for (int count = 1; count < c; count++)
+        {
+            hMac.init(param);
+            hMac.update(state, 0, state.length);
+            hMac.doFinal(state, 0);
+
+            for (int j = 0; j != state.length; j++)
+            {
+                out[outOff + j] ^= state[j];
+            }
+        }
+    }
+
+    private void intToOctet(
+        byte[]  buf,
+        int     i)
+    {
+        buf[0] = (byte)(i >>> 24);
+        buf[1] = (byte)(i >>> 16);
+        buf[2] = (byte)(i >>> 8);
+        buf[3] = (byte)i;
+    }
+
+    private byte[] generateDerivedKey(
+        int dkLen)
+    {
+        int     hLen = hMac.getMacSize();
+        int     l = (dkLen + hLen - 1) / hLen;
+        byte[]  iBuf = new byte[4];
+        byte[]  out = new byte[l * hLen];
+
+        for (int i = 1; i <= l; i++)
+        {
+            intToOctet(iBuf, i);
+
+            F(password, salt, iterationCount, iBuf, out, (i - 1) * hLen);
+        }
+
+        return out;
+    }
+
+    /**
+     * Generate a key parameter derived from the password, salt, and iteration
+     * count we are currently initialised with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @return a KeyParameter object.
+     */
+    public CipherParameters generateDerivedParameters(
+        int keySize)
+    {
+        keySize = keySize / 8;
+
+        byte[]  dKey = generateDerivedKey(keySize);
+
+        return new KeyParameter(dKey, 0, keySize);
+    }
+
+    /**
+     * Generate a key with initialisation vector parameter derived from
+     * the password, salt, and iteration count we are currently initialised
+     * with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @param ivSize the size of the iv we want (in bits)
+     * @return a ParametersWithIV object.
+     */
+    public CipherParameters generateDerivedParameters(
+        int     keySize,
+        int     ivSize)
+    {
+        keySize = keySize / 8;
+        ivSize = ivSize / 8;
+
+        byte[]  dKey = generateDerivedKey(keySize + ivSize);
+
+        return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
+    }
+
+    /**
+     * Generate a key parameter for use with a MAC derived from the password,
+     * salt, and iteration count we are currently initialised with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @return a KeyParameter object.
+     */
+    public CipherParameters generateDerivedMacParameters(
+        int keySize)
+    {
+        return generateDerivedParameters(keySize);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java
new file mode 100644
index 0000000..b881104
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java
@@ -0,0 +1,142 @@
+package org.bouncycastle.crypto.generators;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+
+/**
+ * an RSA key pair generator.
+ */
+public class RSAKeyPairGenerator
+    implements AsymmetricCipherKeyPairGenerator
+{
+    private static BigInteger ONE = BigInteger.valueOf(1);
+
+    private RSAKeyGenerationParameters param;
+
+    public void init(
+        KeyGenerationParameters param)
+    {
+        this.param = (RSAKeyGenerationParameters)param;
+    }
+
+    public AsymmetricCipherKeyPair generateKeyPair()
+    {
+        BigInteger    p, q, n, d, e, pSub1, qSub1, phi;
+
+        //
+        // p and q values should have a length of half the strength in bits
+        //
+        int pbitlength = (param.getStrength() + 1) / 2;
+        int qbitlength = (param.getStrength() - pbitlength);
+
+        e = param.getPublicExponent();
+
+        //
+        // generate p, prime and (p-1) relatively prime to e
+        //
+        for (;;)
+        {
+            p = new BigInteger(pbitlength, 1, param.getRandom());
+            
+            if (p.mod(e).equals(ONE))
+            {
+                continue;
+            }
+            
+            if (!p.isProbablePrime(param.getCertainty()))
+            {
+                continue;
+            }
+            
+            if (e.gcd(p.subtract(ONE)).equals(ONE)) 
+            {
+                break;
+            }
+        }
+
+        //
+        // generate a modulus of the required length
+        //
+        for (;;)
+        {
+            // generate q, prime and (q-1) relatively prime to e,
+            // and not equal to p
+            //
+            for (;;)
+            {
+                q = new BigInteger(qbitlength, 1, param.getRandom());
+                
+                if (q.equals(p))
+                {
+                    continue;
+                }
+                
+                if (q.mod(e).equals(ONE))
+                {
+                    continue;
+                }
+            
+                if (!q.isProbablePrime(param.getCertainty()))
+                {
+                    continue;
+                }
+            
+                if (e.gcd(q.subtract(ONE)).equals(ONE)) 
+                {
+                    break;
+                } 
+            }
+
+            //
+            // calculate the modulus
+            //
+            n = p.multiply(q);
+
+            if (n.bitLength() == param.getStrength()) 
+            {
+                break;
+            } 
+
+            //
+            // if we get here our primes aren't big enough, make the largest
+            // of the two p and try again
+            //
+            p = p.max(q);
+        }
+
+        if (p.compareTo(q) < 0)
+        {
+            phi = p;
+            p = q;
+            q = phi;
+        }
+
+        pSub1 = p.subtract(ONE);
+        qSub1 = q.subtract(ONE);
+        phi = pSub1.multiply(qSub1);
+
+        //
+        // calculate the private exponent
+        //
+        d = e.modInverse(phi);
+
+        //
+        // calculate the CRT factors
+        //
+        BigInteger    dP, dQ, qInv;
+
+        dP = d.remainder(pSub1);
+        dQ = d.remainder(qSub1);
+        qInv = q.modInverse(p);
+
+        return new AsymmetricCipherKeyPair(
+                new RSAKeyParameters(false, n, e),
+                new RSAPrivateCrtKeyParameters(n, e, d, p, q, dP, dQ, qInv));
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/io/DigestInputStream.java b/libcore/security/src/main/java/org/bouncycastle/crypto/io/DigestInputStream.java
new file mode 100644
index 0000000..ef0b03e
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/io/DigestInputStream.java
@@ -0,0 +1,52 @@
+package org.bouncycastle.crypto.io;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.bouncycastle.crypto.Digest;
+
+public class DigestInputStream
+    extends FilterInputStream
+{
+    protected Digest digest;
+
+    public DigestInputStream(
+        InputStream stream,
+        Digest      digest)
+    {
+        super(stream);
+        this.digest = digest;
+    }
+
+    public int read()
+        throws IOException
+    {
+        int b = in.read();
+
+        if (b >= 0)
+        {
+            digest.update((byte)b);
+        }
+        return b;
+    }
+
+    public int read(
+        byte[] b,
+        int off,
+        int len)
+        throws IOException
+    {
+        int n = in.read(b, off, len);
+        if (n > 0)
+        {
+            digest.update(b, off, n);
+        }
+        return n;
+    }
+
+    public Digest getDigest()
+    {
+        return digest;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/io/DigestOutputStream.java b/libcore/security/src/main/java/org/bouncycastle/crypto/io/DigestOutputStream.java
new file mode 100644
index 0000000..2907954
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/io/DigestOutputStream.java
@@ -0,0 +1,43 @@
+package org.bouncycastle.crypto.io;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.bouncycastle.crypto.Digest;
+
+public class DigestOutputStream
+    extends FilterOutputStream
+{
+    protected Digest digest;
+
+    public DigestOutputStream(
+        OutputStream    stream,
+        Digest          digest)
+    {
+        super(stream);
+        this.digest = digest;
+    }
+
+    public void write(int b)
+        throws IOException
+    {
+        digest.update((byte)b);
+        out.write(b);
+    }
+
+    public void write(
+        byte[] b,
+        int off,
+        int len)
+        throws IOException
+    {
+        digest.update(b, off, len);
+        out.write(b, off, len);
+    }
+
+    public Digest getDigest()
+    {
+        return digest;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/io/MacInputStream.java b/libcore/security/src/main/java/org/bouncycastle/crypto/io/MacInputStream.java
new file mode 100644
index 0000000..b78548c
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/io/MacInputStream.java
@@ -0,0 +1,52 @@
+package org.bouncycastle.crypto.io;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.bouncycastle.crypto.Mac;
+
+public class MacInputStream
+    extends FilterInputStream
+{
+    protected Mac mac;
+
+    public MacInputStream(
+        InputStream stream,
+        Mac         mac)
+    {
+        super(stream);
+        this.mac = mac;
+    }
+
+    public int read()
+        throws IOException
+    {
+        int b = in.read();
+
+        if (b >= 0)
+        {
+            mac.update((byte)b);
+        }
+        return b;
+    }
+
+    public int read(
+        byte[] b,
+        int off,
+        int len)
+        throws IOException
+    {
+        int n = in.read(b, off, len);
+        if (n >= 0)
+        {
+            mac.update(b, off, n);
+        }
+        return n;
+    }
+
+    public Mac getMac()
+    {
+        return mac;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/io/MacOutputStream.java b/libcore/security/src/main/java/org/bouncycastle/crypto/io/MacOutputStream.java
new file mode 100644
index 0000000..2cac1c3
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/io/MacOutputStream.java
@@ -0,0 +1,44 @@
+package org.bouncycastle.crypto.io;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.bouncycastle.crypto.Mac;
+
+public class MacOutputStream
+    extends FilterOutputStream
+{
+    protected Mac mac;
+
+    public MacOutputStream(
+        OutputStream stream,
+        Mac          mac)
+    {
+        super(stream);
+        this.mac = mac;
+    }
+
+    public void write(int b)
+        throws IOException
+    {
+        mac.update((byte)b);
+        out.write(b);
+    }
+
+    public void write(
+        byte[] b,
+        int off,
+        int len)
+        throws IOException
+    {
+        mac.update(b, off, len);
+        out.write(b, off, len);
+    }
+
+    public Mac getMac()
+    {
+        return mac;
+    }
+}
+
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/macs/BlockCipherMac.java b/libcore/security/src/main/java/org/bouncycastle/crypto/macs/BlockCipherMac.java
new file mode 100644
index 0000000..b0f3c0b
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/macs/BlockCipherMac.java
@@ -0,0 +1,176 @@
+package org.bouncycastle.crypto.macs;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
+
+public class BlockCipherMac
+    implements Mac
+{
+    private byte[]          mac;
+
+    private byte[]          buf;
+    private int             bufOff;
+    private BlockCipher     cipher;
+
+    private int             macSize;
+
+    /**
+     * create a standard MAC based on a block cipher. This will produce an
+     * authentication code half the length of the block size of the cipher.
+     *
+     * @param cipher the cipher to be used as the basis of the MAC generation.
+     * @deprecated use CBCBlockCipherMac
+     */
+    public BlockCipherMac(
+        BlockCipher     cipher)
+    {
+        this(cipher, (cipher.getBlockSize() * 8) / 2);
+    }
+
+    /**
+     * create a standard MAC based on a block cipher with the size of the
+     * MAC been given in bits.
+     * <p>
+     * Note: the size of the MAC must be at least 16 bits (FIPS Publication 113),
+     * and in general should be less than the size of the block cipher as it reduces
+     * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+     *
+     * @param cipher the cipher to be used as the basis of the MAC generation.
+     * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+     * @deprecated use CBCBlockCipherMac
+     */
+    public BlockCipherMac(
+        BlockCipher     cipher,
+        int             macSizeInBits)
+    {
+        if ((macSizeInBits % 8) != 0)
+        {
+            throw new IllegalArgumentException("MAC size must be multiple of 8");
+        }
+
+        this.cipher = new CBCBlockCipher(cipher);
+        this.macSize = macSizeInBits / 8;
+
+        mac = new byte[cipher.getBlockSize()];
+
+        buf = new byte[cipher.getBlockSize()];
+        bufOff = 0;
+    }
+
+    public String getAlgorithmName()
+    {
+        return cipher.getAlgorithmName();
+    }
+
+    public void init(
+        CipherParameters    params)
+    {
+        reset();
+
+        cipher.init(true, params);
+    }
+
+    public int getMacSize()
+    {
+        return macSize;
+    }
+
+    public void update(
+        byte        in)
+    {
+        int         resultLen = 0;
+
+        if (bufOff == buf.length)
+        {
+            resultLen = cipher.processBlock(buf, 0, mac, 0);
+            bufOff = 0;
+        }
+
+        buf[bufOff++] = in;
+    }
+
+    public void update(
+        byte[]      in,
+        int         inOff,
+        int         len)
+    {
+        if (len < 0)
+        {
+            throw new IllegalArgumentException("Can't have a negative input length!");
+        }
+
+        int blockSize = cipher.getBlockSize();
+        int resultLen = 0;
+        int gapLen = blockSize - bufOff;
+
+        if (len > gapLen)
+        {
+            System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+            resultLen += cipher.processBlock(buf, 0, mac, 0);
+
+            bufOff = 0;
+            len -= gapLen;
+            inOff += gapLen;
+
+            while (len > blockSize)
+            {
+                resultLen += cipher.processBlock(in, inOff, mac, 0);
+
+                len -= blockSize;
+                inOff += blockSize;
+            }
+        }
+
+        System.arraycopy(in, inOff, buf, bufOff, len);
+
+        bufOff += len;
+    }
+
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+    {
+        int blockSize = cipher.getBlockSize();
+
+        //
+        // pad with zeroes
+        //
+        while (bufOff < blockSize)
+        {
+            buf[bufOff] = 0;
+            bufOff++;
+        }
+
+        cipher.processBlock(buf, 0, mac, 0);
+
+        System.arraycopy(mac, 0, out, outOff, macSize);
+
+        reset();
+
+        return macSize;
+    }
+
+    /**
+     * Reset the mac generator.
+     */
+    public void reset()
+    {
+        /*
+         * clean the buffer.
+         */
+        for (int i = 0; i < buf.length; i++)
+        {
+            buf[i] = 0;
+        }
+
+        bufOff = 0;
+
+        /*
+         * reset the underlying cipher.
+         */
+        cipher.reset();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/macs/CBCBlockCipherMac.java b/libcore/security/src/main/java/org/bouncycastle/crypto/macs/CBCBlockCipherMac.java
new file mode 100644
index 0000000..e283df2
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/macs/CBCBlockCipherMac.java
@@ -0,0 +1,232 @@
+package org.bouncycastle.crypto.macs;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.paddings.BlockCipherPadding;
+
+/**
+ * standard CBC Block Cipher MAC - if no padding is specified the default of
+ * pad of zeroes is used.
+ */
+public class CBCBlockCipherMac
+    implements Mac
+{
+    private byte[]              mac;
+
+    private byte[]              buf;
+    private int                 bufOff;
+    private BlockCipher         cipher;
+    private BlockCipherPadding  padding;
+
+    private int                 macSize;
+
+    /**
+     * create a standard MAC based on a CBC block cipher. This will produce an
+     * authentication code half the length of the block size of the cipher.
+     *
+     * @param cipher the cipher to be used as the basis of the MAC generation.
+     */
+    public CBCBlockCipherMac(
+        BlockCipher     cipher)
+    {
+        this(cipher, (cipher.getBlockSize() * 8) / 2, null);
+    }
+
+    /**
+     * create a standard MAC based on a CBC block cipher. This will produce an
+     * authentication code half the length of the block size of the cipher.
+     *
+     * @param cipher the cipher to be used as the basis of the MAC generation.
+     * @param padding the padding to be used to complete the last block.
+     */
+    public CBCBlockCipherMac(
+        BlockCipher         cipher,
+        BlockCipherPadding  padding)
+    {
+        this(cipher, (cipher.getBlockSize() * 8) / 2, padding);
+    }
+
+    /**
+     * create a standard MAC based on a block cipher with the size of the
+     * MAC been given in bits. This class uses CBC mode as the basis for the
+     * MAC generation.
+     * <p>
+     * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+     * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+     * and in general should be less than the size of the block cipher as it reduces
+     * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+     *
+     * @param cipher the cipher to be used as the basis of the MAC generation.
+     * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+     */
+    public CBCBlockCipherMac(
+        BlockCipher     cipher,
+        int             macSizeInBits)
+    {
+        this(cipher, macSizeInBits, null);
+    }
+
+    /**
+     * create a standard MAC based on a block cipher with the size of the
+     * MAC been given in bits. This class uses CBC mode as the basis for the
+     * MAC generation.
+     * <p>
+     * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+     * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+     * and in general should be less than the size of the block cipher as it reduces
+     * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+     *
+     * @param cipher the cipher to be used as the basis of the MAC generation.
+     * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+     * @param padding the padding to be used to complete the last block.
+     */
+    public CBCBlockCipherMac(
+        BlockCipher         cipher,
+        int                 macSizeInBits,
+        BlockCipherPadding  padding)
+    {
+        if ((macSizeInBits % 8) != 0)
+        {
+            throw new IllegalArgumentException("MAC size must be multiple of 8");
+        }
+
+        this.cipher = new CBCBlockCipher(cipher);
+        this.padding = padding;
+        this.macSize = macSizeInBits / 8;
+
+        mac = new byte[cipher.getBlockSize()];
+
+        buf = new byte[cipher.getBlockSize()];
+        bufOff = 0;
+    }
+
+    public String getAlgorithmName()
+    {
+        return cipher.getAlgorithmName();
+    }
+
+    public void init(
+        CipherParameters    params)
+    {
+        reset();
+
+        cipher.init(true, params);
+    }
+
+    public int getMacSize()
+    {
+        return macSize;
+    }
+
+    public void update(
+        byte        in)
+    {
+        int         resultLen = 0;
+
+        if (bufOff == buf.length)
+        {
+            resultLen = cipher.processBlock(buf, 0, mac, 0);
+            bufOff = 0;
+        }
+
+        buf[bufOff++] = in;
+    }
+
+    public void update(
+        byte[]      in,
+        int         inOff,
+        int         len)
+    {
+        if (len < 0)
+        {
+            throw new IllegalArgumentException("Can't have a negative input length!");
+        }
+
+        int blockSize = cipher.getBlockSize();
+        int resultLen = 0;
+        int gapLen = blockSize - bufOff;
+
+        if (len > gapLen)
+        {
+            System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+            resultLen += cipher.processBlock(buf, 0, mac, 0);
+
+            bufOff = 0;
+            len -= gapLen;
+            inOff += gapLen;
+
+            while (len > blockSize)
+            {
+                resultLen += cipher.processBlock(in, inOff, mac, 0);
+
+                len -= blockSize;
+                inOff += blockSize;
+            }
+        }
+
+        System.arraycopy(in, inOff, buf, bufOff, len);
+
+        bufOff += len;
+    }
+
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+    {
+        int blockSize = cipher.getBlockSize();
+
+        if (padding == null)
+        {
+            //
+            // pad with zeroes
+            //
+            while (bufOff < blockSize)
+            {
+                buf[bufOff] = 0;
+                bufOff++;
+            }
+        }
+        else
+        {
+            if (bufOff == blockSize)
+            {
+                cipher.processBlock(buf, 0, mac, 0);
+                bufOff = 0;
+            }
+
+            padding.addPadding(buf, bufOff);
+        }
+
+        cipher.processBlock(buf, 0, mac, 0);
+
+        System.arraycopy(mac, 0, out, outOff, macSize);
+
+        reset();
+
+        return macSize;
+    }
+
+    /**
+     * Reset the mac generator.
+     */
+    public void reset()
+    {
+        /*
+         * clean the buffer.
+         */
+        for (int i = 0; i < buf.length; i++)
+        {
+            buf[i] = 0;
+        }
+
+        bufOff = 0;
+
+        /*
+         * reset the underlying cipher.
+         */
+        cipher.reset();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/macs/CFBBlockCipherMac.java b/libcore/security/src/main/java/org/bouncycastle/crypto/macs/CFBBlockCipherMac.java
new file mode 100644
index 0000000..1a0395e
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/macs/CFBBlockCipherMac.java
@@ -0,0 +1,390 @@
+package org.bouncycastle.crypto.macs;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.paddings.BlockCipherPadding;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
+ */
+class MacCFBBlockCipher
+{
+    private byte[]          IV;
+    private byte[]          cfbV;
+    private byte[]          cfbOutV;
+
+    private int                 blockSize;
+    private BlockCipher         cipher = null;
+
+    /**
+     * Basic constructor.
+     *
+     * @param cipher the block cipher to be used as the basis of the
+     * feedback mode.
+     * @param blockSize the block size in bits (note: a multiple of 8)
+     */
+    public MacCFBBlockCipher(
+        BlockCipher         cipher,
+        int                 bitBlockSize)
+    {
+        this.cipher = cipher;
+        this.blockSize = bitBlockSize / 8;
+
+        this.IV = new byte[cipher.getBlockSize()];
+        this.cfbV = new byte[cipher.getBlockSize()];
+        this.cfbOutV = new byte[cipher.getBlockSize()];
+    }
+
+    /**
+     * Initialise the cipher and, possibly, the initialisation vector (IV).
+     * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+     * An IV which is too short is handled in FIPS compliant fashion.
+     *
+     * @param param the key and other data required by the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        CipherParameters    params)
+        throws IllegalArgumentException
+    {
+        if (params instanceof ParametersWithIV)
+        {
+                ParametersWithIV ivParam = (ParametersWithIV)params;
+                byte[]      iv = ivParam.getIV();
+
+                if (iv.length < IV.length)
+                {
+                    System.arraycopy(iv, 0, IV, IV.length - iv.length, iv.length);
+                }
+                else
+                {
+                    System.arraycopy(iv, 0, IV, 0, IV.length);
+                }
+
+                reset();
+
+                cipher.init(true, ivParam.getParameters());
+        }
+        else
+        {
+                reset();
+
+                cipher.init(true, params);
+        }
+    }
+
+    /**
+     * return the algorithm name and mode.
+     *
+     * @return the name of the underlying algorithm followed by "/CFB"
+     * and the block size in bits.
+     */
+    public String getAlgorithmName()
+    {
+        return cipher.getAlgorithmName() + "/CFB" + (blockSize * 8);
+    }
+
+    /**
+     * return the block size we are operating at.
+     *
+     * @return the block size we are operating at (in bytes).
+     */
+    public int getBlockSize()
+    {
+        return blockSize;
+    }
+
+    /**
+     * Process one block of input from the array in and write it to
+     * the out array.
+     *
+     * @param in the array containing the input data.
+     * @param inOff offset into the in array the data starts at.
+     * @param out the array the output data will be copied into.
+     * @param outOff the offset into the out array the output will start at.
+     * @exception DataLengthException if there isn't enough data in in, or
+     * space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     * @return the number of bytes processed and produced.
+     */
+    public int processBlock(
+        byte[]      in,
+        int         inOff,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        if ((inOff + blockSize) > in.length)
+        {
+            throw new DataLengthException("input buffer too short");
+        }
+
+        if ((outOff + blockSize) > out.length)
+        {
+            throw new DataLengthException("output buffer too short");
+        }
+
+        cipher.processBlock(cfbV, 0, cfbOutV, 0);
+
+        //
+        // XOR the cfbV with the plaintext producing the cipher text
+        //
+        for (int i = 0; i < blockSize; i++)
+        {
+            out[outOff + i] = (byte)(cfbOutV[i] ^ in[inOff + i]);
+        }
+
+        //
+        // change over the input block.
+        //
+        System.arraycopy(cfbV, blockSize, cfbV, 0, cfbV.length - blockSize);
+        System.arraycopy(out, outOff, cfbV, cfbV.length - blockSize, blockSize);
+
+        return blockSize;
+    }
+
+    /**
+     * reset the chaining vector back to the IV and reset the underlying
+     * cipher.
+     */
+    public void reset()
+    {
+        System.arraycopy(IV, 0, cfbV, 0, IV.length);
+
+        cipher.reset();
+    }
+
+    void getMacBlock(
+        byte[]  mac)
+    {
+        cipher.processBlock(cfbV, 0, mac, 0);
+    }
+}
+
+public class CFBBlockCipherMac
+    implements Mac
+{
+    private byte[]              mac;
+
+    private byte[]              buf;
+    private int                 bufOff;
+    private MacCFBBlockCipher   cipher;
+    private BlockCipherPadding  padding = null;
+
+
+    private int                 macSize;
+
+    /**
+     * create a standard MAC based on a CFB block cipher. This will produce an
+     * authentication code half the length of the block size of the cipher, with
+     * the CFB mode set to 8 bits.
+     *
+     * @param cipher the cipher to be used as the basis of the MAC generation.
+     */
+    public CFBBlockCipherMac(
+        BlockCipher     cipher)
+    {
+        this(cipher, 8, (cipher.getBlockSize() * 8) / 2, null);
+    }
+
+    /**
+     * create a standard MAC based on a CFB block cipher. This will produce an
+     * authentication code half the length of the block size of the cipher, with
+     * the CFB mode set to 8 bits.
+     *
+     * @param cipher the cipher to be used as the basis of the MAC generation.
+     * @param padding the padding to be used.
+     */
+    public CFBBlockCipherMac(
+        BlockCipher         cipher,
+        BlockCipherPadding  padding)
+    {
+        this(cipher, 8, (cipher.getBlockSize() * 8) / 2, padding);
+    }
+
+    /**
+     * create a standard MAC based on a block cipher with the size of the
+     * MAC been given in bits. This class uses CFB mode as the basis for the
+     * MAC generation.
+     * <p>
+     * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+     * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+     * and in general should be less than the size of the block cipher as it reduces
+     * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+     *
+     * @param cipher the cipher to be used as the basis of the MAC generation.
+     * @param cfbBitSize the size of an output block produced by the CFB mode.
+     * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+     */
+    public CFBBlockCipherMac(
+        BlockCipher         cipher,
+        int                 cfbBitSize,
+        int                 macSizeInBits)
+    {
+        this(cipher, cfbBitSize, macSizeInBits, null);
+    }
+
+    /**
+     * create a standard MAC based on a block cipher with the size of the
+     * MAC been given in bits. This class uses CFB mode as the basis for the
+     * MAC generation.
+     * <p>
+     * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+     * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+     * and in general should be less than the size of the block cipher as it reduces
+     * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+     *
+     * @param cipher the cipher to be used as the basis of the MAC generation.
+     * @param cfbBitSize the size of an output block produced by the CFB mode.
+     * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+     * @param padding a padding to be used.
+     */
+    public CFBBlockCipherMac(
+        BlockCipher         cipher,
+        int                 cfbBitSize,
+        int                 macSizeInBits,
+        BlockCipherPadding  padding)
+    {
+        if ((macSizeInBits % 8) != 0)
+        {
+            throw new IllegalArgumentException("MAC size must be multiple of 8");
+        }
+
+        mac = new byte[cipher.getBlockSize()];
+
+        this.cipher = new MacCFBBlockCipher(cipher, cfbBitSize);
+        this.padding = padding;
+        this.macSize = macSizeInBits / 8;
+
+        buf = new byte[this.cipher.getBlockSize()];
+        bufOff = 0;
+    }
+
+    public String getAlgorithmName()
+    {
+        return cipher.getAlgorithmName();
+    }
+
+    public void init(
+        CipherParameters    params)
+    {
+        reset();
+
+        cipher.init(params);
+    }
+
+    public int getMacSize()
+    {
+        return macSize;
+    }
+
+    public void update(
+        byte        in)
+    {
+        int         resultLen = 0;
+
+        if (bufOff == buf.length)
+        {
+            resultLen = cipher.processBlock(buf, 0, mac, 0);
+            bufOff = 0;
+        }
+
+        buf[bufOff++] = in;
+    }
+
+    public void update(
+        byte[]      in,
+        int         inOff,
+        int         len)
+    {
+        if (len < 0)
+        {
+            throw new IllegalArgumentException("Can't have a negative input length!");
+        }
+
+        int blockSize = cipher.getBlockSize();
+        int resultLen = 0;
+        int gapLen = blockSize - bufOff;
+
+        if (len > gapLen)
+        {
+            System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+            resultLen += cipher.processBlock(buf, 0, mac, 0);
+
+            bufOff = 0;
+            len -= gapLen;
+            inOff += gapLen;
+
+            while (len > blockSize)
+            {
+                resultLen += cipher.processBlock(in, inOff, mac, 0);
+
+                len -= blockSize;
+                inOff += blockSize;
+            }
+        }
+
+        System.arraycopy(in, inOff, buf, bufOff, len);
+
+        bufOff += len;
+    }
+
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+    {
+        int blockSize = cipher.getBlockSize();
+
+        //
+        // pad with zeroes
+        //
+        if (this.padding == null)
+        {
+            while (bufOff < blockSize)
+            {
+                buf[bufOff] = 0;
+                bufOff++;
+            }
+        }
+        else
+        {
+            padding.addPadding(buf, bufOff);
+        }
+
+        cipher.processBlock(buf, 0, mac, 0);
+
+        cipher.getMacBlock(mac);
+
+        System.arraycopy(mac, 0, out, outOff, macSize);
+
+        reset();
+
+        return macSize;
+    }
+
+    /**
+     * Reset the mac generator.
+     */
+    public void reset()
+    {
+        /*
+         * clean the buffer.
+         */
+        for (int i = 0; i < buf.length; i++)
+        {
+            buf[i] = 0;
+        }
+
+        bufOff = 0;
+
+        /*
+         * reset the underlying cipher.
+         */
+        cipher.reset();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/macs/HMac.java b/libcore/security/src/main/java/org/bouncycastle/crypto/macs/HMac.java
new file mode 100644
index 0000000..0bd4d39
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/macs/HMac.java
@@ -0,0 +1,199 @@
+package org.bouncycastle.crypto.macs;
+
+import java.util.Hashtable;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.ExtendedDigest;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.params.KeyParameter;
+
+/**
+ * HMAC implementation based on RFC2104
+ *
+ * H(K XOR opad, H(K XOR ipad, text))
+ */
+public class HMac
+    implements Mac
+{
+    private final static byte IPAD = (byte)0x36;
+    private final static byte OPAD = (byte)0x5C;
+
+    private Digest digest;
+    private int digestSize;
+    private int blockLength;
+    
+    private byte[] inputPad;
+    private byte[] outputPad;
+
+    private static Hashtable blockLengths;
+    
+    static
+    {
+        blockLengths = new Hashtable();
+        
+        blockLengths.put("GOST3411", new Integer(32));
+        
+        blockLengths.put("MD2", new Integer(16));
+        blockLengths.put("MD4", new Integer(64));
+        blockLengths.put("MD5", new Integer(64));
+        
+        blockLengths.put("RIPEMD128", new Integer(64));
+        blockLengths.put("RIPEMD160", new Integer(64));
+        
+        blockLengths.put("SHA-1", new Integer(64));
+        blockLengths.put("SHA-224", new Integer(64));
+        blockLengths.put("SHA-256", new Integer(64));
+        blockLengths.put("SHA-384", new Integer(128));
+        blockLengths.put("SHA-512", new Integer(128));
+        
+        blockLengths.put("Tiger", new Integer(64));
+        blockLengths.put("Whirlpool", new Integer(64));
+    }
+    
+    private static int getByteLength(
+        Digest digest)
+    {
+        if (digest instanceof ExtendedDigest)
+        {
+            return ((ExtendedDigest)digest).getByteLength();
+        }
+        
+        Integer  b = (Integer)blockLengths.get(digest.getAlgorithmName());
+        
+        if (b == null)
+        {       
+            throw new IllegalArgumentException("unknown digest passed: " + digest.getAlgorithmName());
+        }
+        
+        return b.intValue();
+    }
+    
+    /**
+     * Base constructor for one of the standard digest algorithms that the 
+     * byteLength of the algorithm is know for.
+     * 
+     * @param digest the digest.
+     */
+    public HMac(
+        Digest digest)
+    {
+        this(digest, getByteLength(digest));
+    }
+
+    private HMac(
+        Digest digest,
+        int    byteLength)
+    {
+        this.digest = digest;
+        digestSize = digest.getDigestSize();
+
+        this.blockLength = byteLength;
+
+        inputPad = new byte[blockLength];
+        outputPad = new byte[blockLength];
+    }
+    
+    public String getAlgorithmName()
+    {
+        return digest.getAlgorithmName() + "/HMAC";
+    }
+
+    public Digest getUnderlyingDigest()
+    {
+        return digest;
+    }
+
+    public void init(
+        CipherParameters params)
+    {
+        digest.reset();
+
+        byte[] key = ((KeyParameter)params).getKey();
+
+        if (key.length > blockLength)
+        {
+            digest.update(key, 0, key.length);
+            digest.doFinal(inputPad, 0);
+            for (int i = digestSize; i < inputPad.length; i++)
+            {
+                inputPad[i] = 0;
+            }
+        }
+        else
+        {
+            System.arraycopy(key, 0, inputPad, 0, key.length);
+            for (int i = key.length; i < inputPad.length; i++)
+            {
+                inputPad[i] = 0;
+            }
+        }
+
+        outputPad = new byte[inputPad.length];
+        System.arraycopy(inputPad, 0, outputPad, 0, inputPad.length);
+
+        for (int i = 0; i < inputPad.length; i++)
+        {
+            inputPad[i] ^= IPAD;
+        }
+
+        for (int i = 0; i < outputPad.length; i++)
+        {
+            outputPad[i] ^= OPAD;
+        }
+
+        digest.update(inputPad, 0, inputPad.length);
+    }
+
+    public int getMacSize()
+    {
+        return digestSize;
+    }
+
+    public void update(
+        byte in)
+    {
+        digest.update(in);
+    }
+
+    public void update(
+        byte[] in,
+        int inOff,
+        int len)
+    {
+        digest.update(in, inOff, len);
+    }
+
+    public int doFinal(
+        byte[] out,
+        int outOff)
+    {
+        byte[] tmp = new byte[digestSize];
+        digest.doFinal(tmp, 0);
+
+        digest.update(outputPad, 0, outputPad.length);
+        digest.update(tmp, 0, tmp.length);
+
+        int     len = digest.doFinal(out, outOff);
+
+        reset();
+
+        return len;
+    }
+
+    /**
+     * Reset the mac generator.
+     */
+    public void reset()
+    {
+        /*
+         * reset the underlying digest.
+         */
+        digest.reset();
+
+        /*
+         * reinitialize the digest.
+         */
+        digest.update(inputPad, 0, inputPad.length);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/macs/ISO9797Alg3Mac.java b/libcore/security/src/main/java/org/bouncycastle/crypto/macs/ISO9797Alg3Mac.java
new file mode 100644
index 0000000..11db130
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/macs/ISO9797Alg3Mac.java
@@ -0,0 +1,289 @@
+package org.bouncycastle.crypto.macs;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.engines.DESEngine;
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.paddings.BlockCipherPadding;
+import org.bouncycastle.crypto.params.KeyParameter;
+
+/**
+ * DES based CBC Block Cipher MAC according to ISO9797, algorithm 3 (ANSI X9.19 Retail MAC)
+ *
+ * This could as well be derived from CBCBlockCipherMac, but then the property mac in the base
+ * class must be changed to protected  
+ */
+
+public class ISO9797Alg3Mac 
+    implements Mac 
+{
+    private byte[]              mac;
+    
+    private byte[]              buf;
+    private int                 bufOff;
+    private BlockCipher         cipher;
+    private BlockCipherPadding  padding;
+    
+    private int                 macSize;
+    private KeyParameter        lastKey2;
+    private KeyParameter        lastKey3;
+    
+    /**
+     * create a Retail-MAC based on a CBC block cipher. This will produce an
+     * authentication code of the length of the block size of the cipher.
+     *
+     * @param cipher the cipher to be used as the basis of the MAC generation. This must
+     * be DESEngine.
+     */
+    public ISO9797Alg3Mac(
+            BlockCipher     cipher)
+    {
+        this(cipher, cipher.getBlockSize() * 8, null);
+    }
+    
+    /**
+     * create a Retail-MAC based on a CBC block cipher. This will produce an
+     * authentication code of the length of the block size of the cipher.
+     *
+     * @param cipher the cipher to be used as the basis of the MAC generation.
+     * @param padding the padding to be used to complete the last block.
+     */
+    public ISO9797Alg3Mac(
+        BlockCipher         cipher,
+        BlockCipherPadding  padding)
+    {
+        this(cipher, cipher.getBlockSize() * 8, padding);
+    }
+
+    /**
+     * create a Retail-MAC based on a block cipher with the size of the
+     * MAC been given in bits. This class uses single DES CBC mode as the basis for the
+     * MAC generation.
+     * <p>
+     * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+     * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+     * and in general should be less than the size of the block cipher as it reduces
+     * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+     *
+     * @param cipher the cipher to be used as the basis of the MAC generation.
+     * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+     */
+    public ISO9797Alg3Mac(
+        BlockCipher     cipher,
+        int             macSizeInBits)
+    {
+        this(cipher, macSizeInBits, null);
+    }
+
+    /**
+     * create a standard MAC based on a block cipher with the size of the
+     * MAC been given in bits. This class uses single DES CBC mode as the basis for the
+     * MAC generation. The final block is decrypted and then encrypted using the
+     * middle and right part of the key.
+     * <p>
+     * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+     * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+     * and in general should be less than the size of the block cipher as it reduces
+     * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+     *
+     * @param cipher the cipher to be used as the basis of the MAC generation.
+     * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+     * @param padding the padding to be used to complete the last block.
+     */
+    public ISO9797Alg3Mac(
+        BlockCipher         cipher,
+        int                 macSizeInBits,
+        BlockCipherPadding  padding)
+    {
+        if ((macSizeInBits % 8) != 0)
+        {
+            throw new IllegalArgumentException("MAC size must be multiple of 8");
+        }
+
+        if (!(cipher instanceof DESEngine))
+        {
+            throw new IllegalArgumentException("cipher must be instance of DESEngine");
+        }
+
+        this.cipher = new CBCBlockCipher(cipher);
+        this.padding = padding;
+        this.macSize = macSizeInBits / 8;
+
+        mac = new byte[cipher.getBlockSize()];
+
+        buf = new byte[cipher.getBlockSize()];
+        bufOff = 0;
+    }
+    
+    public String getAlgorithmName()
+    {
+        return "ISO9797Alg3";
+    }
+
+    public void init(CipherParameters params)
+    {
+        reset();
+
+        if (!(params instanceof KeyParameter))
+        {
+            throw new IllegalArgumentException(
+                    "params must be an instance of KeyParameter");
+        }
+
+        // KeyParameter must contain a double or triple length DES key,
+        // however the underlying cipher is a single DES. The middle and
+        // right key are used only in the final step.
+
+        KeyParameter kp = (KeyParameter)params;
+        KeyParameter key1;
+        byte[] keyvalue = kp.getKey();
+
+        if (keyvalue.length == 16)
+        { // Double length DES key
+            key1 = new KeyParameter(keyvalue, 0, 8);
+            this.lastKey2 = new KeyParameter(keyvalue, 8, 8);
+            this.lastKey3 = key1;
+        }
+        else if (keyvalue.length == 24)
+        { // Triple length DES key
+            key1 = new KeyParameter(keyvalue, 0, 8);
+            this.lastKey2 = new KeyParameter(keyvalue, 8, 8);
+            this.lastKey3 = new KeyParameter(keyvalue, 16, 8);
+        }
+        else
+        {
+            throw new IllegalArgumentException(
+                    "Key must be either 112 or 168 bit long");
+        }
+
+        cipher.init(true, key1);
+    }
+    
+    public int getMacSize()
+    {
+        return macSize;
+    }
+    
+    public void update(
+            byte        in)
+    {
+        int         resultLen = 0;
+        
+        if (bufOff == buf.length)
+        {
+            resultLen = cipher.processBlock(buf, 0, mac, 0);
+            bufOff = 0;
+        }
+        
+        buf[bufOff++] = in;
+    }
+    
+    
+    public void update(
+            byte[]      in,
+            int         inOff,
+            int         len)
+    {
+        if (len < 0)
+        {
+            throw new IllegalArgumentException("Can't have a negative input length!");
+        }
+        
+        int blockSize = cipher.getBlockSize();
+        int resultLen = 0;
+        int gapLen = blockSize - bufOff;
+        
+        if (len > gapLen)
+        {
+            System.arraycopy(in, inOff, buf, bufOff, gapLen);
+            
+            resultLen += cipher.processBlock(buf, 0, mac, 0);
+            
+            bufOff = 0;
+            len -= gapLen;
+            inOff += gapLen;
+            
+            while (len > blockSize)
+            {
+                resultLen += cipher.processBlock(in, inOff, mac, 0);
+                
+                len -= blockSize;
+                inOff += blockSize;
+            }
+        }
+        
+        System.arraycopy(in, inOff, buf, bufOff, len);
+        
+        bufOff += len;
+    }
+    
+    public int doFinal(
+            byte[]  out,
+            int     outOff)
+    {
+        int blockSize = cipher.getBlockSize();
+        
+        if (padding == null)
+        {
+            //
+            // pad with zeroes
+            //
+            while (bufOff < blockSize)
+            {
+                buf[bufOff] = 0;
+                bufOff++;
+            }
+        }
+        else
+        {
+            if (bufOff == blockSize)
+            {
+                cipher.processBlock(buf, 0, mac, 0);
+                bufOff = 0;
+            }
+            
+            padding.addPadding(buf, bufOff);
+        }
+        
+        cipher.processBlock(buf, 0, mac, 0);
+
+        // Added to code from base class
+        DESEngine deseng = new DESEngine();
+        
+        deseng.init(false, this.lastKey2);
+        deseng.processBlock(mac, 0, mac, 0);
+        
+        deseng.init(true, this.lastKey3);
+        deseng.processBlock(mac, 0, mac, 0);
+        // ****
+        
+        System.arraycopy(mac, 0, out, outOff, macSize);
+        
+        reset();
+        
+        return macSize;
+    }
+
+    
+    /**
+     * Reset the mac generator.
+     */
+    public void reset()
+    {
+        /*
+         * clean the buffer.
+         */
+        for (int i = 0; i < buf.length; i++)
+        {
+            buf[i] = 0;
+        }
+        
+        bufOff = 0;
+        
+        /*
+         * reset the underlying cipher.
+         */
+        cipher.reset();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/macs/OldHMac.java b/libcore/security/src/main/java/org/bouncycastle/crypto/macs/OldHMac.java
new file mode 100644
index 0000000..7463afd
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/macs/OldHMac.java
@@ -0,0 +1,138 @@
+package org.bouncycastle.crypto.macs;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.params.KeyParameter;
+
+/**
+ * HMAC implementation based on RFC2104
+ *
+ * H(K XOR opad, H(K XOR ipad, text))
+ */
+public class OldHMac
+implements Mac
+{
+    private final static int BLOCK_LENGTH = 64;
+
+    private final static byte IPAD = (byte)0x36;
+    private final static byte OPAD = (byte)0x5C;
+
+    private Digest digest;
+    private int digestSize;
+    private byte[] inputPad = new byte[BLOCK_LENGTH];
+    private byte[] outputPad = new byte[BLOCK_LENGTH];
+
+    /**
+     * @deprecated uses incorrect pad for SHA-512 and SHA-384 use HMac.
+     */
+    public OldHMac(
+        Digest digest)
+    {
+        this.digest = digest;
+        digestSize = digest.getDigestSize();
+    }
+
+    public String getAlgorithmName()
+    {
+        return digest.getAlgorithmName() + "/HMAC";
+    }
+
+    public Digest getUnderlyingDigest()
+    {
+        return digest;
+    }
+
+    public void init(
+        CipherParameters params)
+    {
+        digest.reset();
+
+        byte[] key = ((KeyParameter)params).getKey();
+
+        if (key.length > BLOCK_LENGTH)
+        {
+            digest.update(key, 0, key.length);
+            digest.doFinal(inputPad, 0);
+            for (int i = digestSize; i < inputPad.length; i++)
+            {
+                inputPad[i] = 0;
+            }
+        }
+        else
+        {
+            System.arraycopy(key, 0, inputPad, 0, key.length);
+            for (int i = key.length; i < inputPad.length; i++)
+            {
+                inputPad[i] = 0;
+            }
+        }
+
+        outputPad = new byte[inputPad.length];
+        System.arraycopy(inputPad, 0, outputPad, 0, inputPad.length);
+
+        for (int i = 0; i < inputPad.length; i++)
+        {
+            inputPad[i] ^= IPAD;
+        }
+
+        for (int i = 0; i < outputPad.length; i++)
+        {
+            outputPad[i] ^= OPAD;
+        }
+
+        digest.update(inputPad, 0, inputPad.length);
+    }
+
+    public int getMacSize()
+    {
+        return digestSize;
+    }
+
+    public void update(
+        byte in)
+    {
+        digest.update(in);
+    }
+
+    public void update(
+        byte[] in,
+        int inOff,
+        int len)
+    {
+        digest.update(in, inOff, len);
+    }
+
+    public int doFinal(
+        byte[] out,
+        int outOff)
+    {
+        byte[] tmp = new byte[digestSize];
+        digest.doFinal(tmp, 0);
+
+        digest.update(outputPad, 0, outputPad.length);
+        digest.update(tmp, 0, tmp.length);
+
+        int     len = digest.doFinal(out, outOff);
+
+        reset();
+
+        return len;
+    }
+
+    /**
+     * Reset the mac generator.
+     */
+    public void reset()
+    {
+        /*
+         * reset the underlying digest.
+         */
+        digest.reset();
+
+        /*
+         * reinitialize the digest.
+         */
+        digest.update(inputPad, 0, inputPad.length);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/modes/CBCBlockCipher.java b/libcore/security/src/main/java/org/bouncycastle/crypto/modes/CBCBlockCipher.java
new file mode 100644
index 0000000..7640045
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/modes/CBCBlockCipher.java
@@ -0,0 +1,233 @@
+package org.bouncycastle.crypto.modes;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * implements Cipher-Block-Chaining (CBC) mode on top of a simple cipher.
+ */
+public class CBCBlockCipher
+    implements BlockCipher
+{
+    private byte[]          IV;
+    private byte[]          cbcV;
+    private byte[]          cbcNextV;
+
+    private int             blockSize;
+    private BlockCipher     cipher = null;
+    private boolean         encrypting;
+
+    /**
+     * Basic constructor.
+     *
+     * @param cipher the block cipher to be used as the basis of chaining.
+     */
+    public CBCBlockCipher(
+        BlockCipher cipher)
+    {
+        this.cipher = cipher;
+        this.blockSize = cipher.getBlockSize();
+
+        this.IV = new byte[blockSize];
+        this.cbcV = new byte[blockSize];
+        this.cbcNextV = new byte[blockSize];
+    }
+
+    /**
+     * return the underlying block cipher that we are wrapping.
+     *
+     * @return the underlying block cipher that we are wrapping.
+     */
+    public BlockCipher getUnderlyingCipher()
+    {
+        return cipher;
+    }
+
+    /**
+     * Initialise the cipher and, possibly, the initialisation vector (IV).
+     * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+     *
+     * @param encrypting if true the cipher is initialised for
+     *  encryption, if false for decryption.
+     * @param params the key and other data required by the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean             encrypting,
+        CipherParameters    params)
+        throws IllegalArgumentException
+    {
+        this.encrypting = encrypting;
+        
+        if (params instanceof ParametersWithIV)
+        {
+                ParametersWithIV ivParam = (ParametersWithIV)params;
+                byte[]      iv = ivParam.getIV();
+
+                if (iv.length != blockSize)
+                {
+                    throw new IllegalArgumentException("initialisation vector must be the same length as block size");
+                }
+
+                System.arraycopy(iv, 0, IV, 0, iv.length);
+
+                reset();
+
+                cipher.init(encrypting, ivParam.getParameters());
+        }
+        else
+        {
+                reset();
+
+                cipher.init(encrypting, params);
+        }
+    }
+
+    /**
+     * return the algorithm name and mode.
+     *
+     * @return the name of the underlying algorithm followed by "/CBC".
+     */
+    public String getAlgorithmName()
+    {
+        return cipher.getAlgorithmName() + "/CBC";
+    }
+
+    /**
+     * return the block size of the underlying cipher.
+     *
+     * @return the block size of the underlying cipher.
+     */
+    public int getBlockSize()
+    {
+        return cipher.getBlockSize();
+    }
+
+    /**
+     * Process one block of input from the array in and write it to
+     * the out array.
+     *
+     * @param in the array containing the input data.
+     * @param inOff offset into the in array the data starts at.
+     * @param out the array the output data will be copied into.
+     * @param outOff the offset into the out array the output will start at.
+     * @exception DataLengthException if there isn't enough data in in, or
+     * space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     * @return the number of bytes processed and produced.
+     */
+    public int processBlock(
+        byte[]      in,
+        int         inOff,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        return (encrypting) ? encryptBlock(in, inOff, out, outOff) : decryptBlock(in, inOff, out, outOff);
+    }
+
+    /**
+     * reset the chaining vector back to the IV and reset the underlying
+     * cipher.
+     */
+    public void reset()
+    {
+        System.arraycopy(IV, 0, cbcV, 0, IV.length);
+
+        cipher.reset();
+    }
+
+    /**
+     * Do the appropriate chaining step for CBC mode encryption.
+     *
+     * @param in the array containing the data to be encrypted.
+     * @param inOff offset into the in array the data starts at.
+     * @param out the array the encrypted data will be copied into.
+     * @param outOff the offset into the out array the output will start at.
+     * @exception DataLengthException if there isn't enough data in in, or
+     * space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     * @return the number of bytes processed and produced.
+     */
+    private int encryptBlock(
+        byte[]      in,
+        int         inOff,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        if ((inOff + blockSize) > in.length)
+        {
+            throw new DataLengthException("input buffer too short");
+        }
+
+        /*
+         * XOR the cbcV and the input,
+         * then encrypt the cbcV
+         */
+        for (int i = 0; i < blockSize; i++)
+        {
+            cbcV[i] ^= in[inOff + i];
+        }
+
+        int length = cipher.processBlock(cbcV, 0, out, outOff);
+
+        /*
+         * copy ciphertext to cbcV
+         */
+        System.arraycopy(out, outOff, cbcV, 0, cbcV.length);
+
+        return length;
+    }
+
+    /**
+     * Do the appropriate chaining step for CBC mode decryption.
+     *
+     * @param in the array containing the data to be decrypted.
+     * @param inOff offset into the in array the data starts at.
+     * @param out the array the decrypted data will be copied into.
+     * @param outOff the offset into the out array the output will start at.
+     * @exception DataLengthException if there isn't enough data in in, or
+     * space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     * @return the number of bytes processed and produced.
+     */
+    private int decryptBlock(
+        byte[]      in,
+        int         inOff,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        if ((inOff + blockSize) > in.length)
+        {
+            throw new DataLengthException("input buffer too short");
+        }
+
+        System.arraycopy(in, inOff, cbcNextV, 0, blockSize);
+
+        int length = cipher.processBlock(in, inOff, out, outOff);
+
+        /*
+         * XOR the cbcV and the output
+         */
+        for (int i = 0; i < blockSize; i++)
+        {
+            out[outOff + i] ^= cbcV[i];
+        }
+
+        /*
+         * swap the back up buffer into next position
+         */
+        byte[]  tmp;
+
+        tmp = cbcV;
+        cbcV = cbcNextV;
+        cbcNextV = tmp;
+
+        return length;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java b/libcore/security/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java
new file mode 100644
index 0000000..95db190
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java
@@ -0,0 +1,284 @@
+package org.bouncycastle.crypto.modes;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
+import org.bouncycastle.crypto.params.CCMParameters;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * Implements the Counter with Cipher Block Chaining mode (CCM) detailed in
+ * NIST Special Publication 800-38C.
+ * <p>
+ * <b>Note</b>: this mode is a packet mode - it needs all the data up front.
+ */
+public class CCMBlockCipher
+{
+    private BlockCipher     cipher = null;
+    private int             blockSize;
+    private boolean         forEncryption;
+    private CCMParameters   params;
+    private byte[]          macBlock;
+
+
+    /**
+     * Basic constructor.
+     *
+     * @param c the block cipher to be used.
+     */
+    public CCMBlockCipher(BlockCipher c)
+    {
+        this.cipher = c;
+        this.blockSize = c.getBlockSize();
+        this.macBlock = new byte[blockSize];
+        
+        if (blockSize != 16)
+        {
+            throw new IllegalArgumentException("cipher required with a block size of 16.");
+        }
+    }
+
+    /**
+     * return the underlying block cipher that we are wrapping.
+     *
+     * @return the underlying block cipher that we are wrapping.
+     */
+    public BlockCipher getUnderlyingCipher()
+    {
+        return cipher;
+    }
+
+
+    public void init(boolean forEncryption, CipherParameters params)
+          throws IllegalArgumentException
+    {
+        if (!(params instanceof CCMParameters))
+        {
+            throw new IllegalArgumentException("parameters need to be CCMParameters");
+        }
+        
+        this.forEncryption = forEncryption;
+        this.params = (CCMParameters)params;
+    }
+
+    public String getAlgorithmName()
+    {
+        return cipher.getAlgorithmName() + "/CCM";
+    }
+    
+    /**
+     * Returns a byte array containing the mac calculated as part of the
+     * last encrypt or decrypt operation.
+     * 
+     * @return the last mac calculated.
+     */
+    public byte[] getMac()
+    {
+        byte[] mac = new byte[params.getMacSize() / 8];
+        
+        System.arraycopy(macBlock, 0, mac, 0, mac.length);
+        
+        return mac;
+    }
+
+    public byte[] processPacket(byte[] in, int inOff, int inLen)
+        throws IllegalStateException, InvalidCipherTextException
+    {
+        if (params == null)
+        {
+            throw new IllegalStateException("CCM cipher unitialized.");
+        }
+        
+        BlockCipher ctrCipher = new SICBlockCipher(cipher);
+        byte[] iv = new byte[blockSize];
+        byte[] nonce = params.getNonce();
+        int    macSize = params.getMacSize() / 8;
+        byte[] out;
+
+        iv[0] = (byte)(((15 - nonce.length) - 1) & 0x7);
+        
+        System.arraycopy(nonce, 0, iv, 1, nonce.length);
+        
+        ctrCipher.init(forEncryption, new ParametersWithIV(params.getKey(), iv));
+        
+        if (forEncryption)
+        {
+            int index = inOff;
+            int outOff = 0;
+            
+            out = new byte[inLen + macSize];
+            
+            calculateMac(in, inOff, inLen, macBlock);
+            
+            ctrCipher.processBlock(macBlock, 0, macBlock, 0);   // S0
+            
+            while (index < inLen - blockSize)                   // S1...
+            {
+                ctrCipher.processBlock(in, index, out, outOff);
+                outOff += blockSize;
+                index += blockSize;
+            }
+            
+            byte[] block = new byte[blockSize];
+            
+            System.arraycopy(in, index, block, 0, inLen - index);
+            
+            ctrCipher.processBlock(block, 0, block, 0);
+            
+            System.arraycopy(block, 0, out, outOff, inLen - index);
+            
+            outOff += inLen - index;
+
+            System.arraycopy(macBlock, 0, out, outOff, out.length - outOff);
+        }
+        else
+        {
+            int index = inOff;
+            int outOff = 0;
+            
+            out = new byte[inLen - macSize];
+            
+            System.arraycopy(in, inOff + inLen - macSize, macBlock, 0, macSize);
+            
+            ctrCipher.processBlock(macBlock, 0, macBlock, 0);
+            
+            for (int i = macSize; i != macBlock.length; i++)
+            {
+                macBlock[i] = 0;
+            }
+            
+            while (outOff < out.length - blockSize)
+            {
+                ctrCipher.processBlock(in, index, out, outOff);
+                outOff += blockSize;
+                index += blockSize;
+            }
+            
+            byte[] block = new byte[blockSize];
+            
+            System.arraycopy(in, index, block, 0, out.length - outOff);
+            
+            ctrCipher.processBlock(block, 0, block, 0);
+            
+            System.arraycopy(block, 0, out, outOff, out.length - outOff);
+            
+            byte[] calculatedMacBlock = new byte[blockSize];
+            
+            calculateMac(out, 0, out.length, calculatedMacBlock);
+            
+            if (!areEqual(macBlock, calculatedMacBlock))
+            {
+                throw new InvalidCipherTextException("mac check in CCM failed");
+            }
+        }
+        
+        return out;
+    }
+    
+    private int calculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock)
+    {
+        Mac    cMac = new CBCBlockCipherMac(cipher, params.getMacSize());
+
+        byte[] nonce = params.getNonce();
+        byte[] associatedText = params.getAssociatedText();
+        
+        cMac.init(params.getKey());
+
+        //
+        // build b0
+        //
+        byte[] b0 = new byte[16];
+    
+        if (associatedText != null && associatedText.length != 0)
+        {
+            b0[0] |= 0x40;
+        }
+        
+        b0[0] |= (((cMac.getMacSize() - 2) / 2) & 0x7) << 3;
+
+        b0[0] |= ((15 - nonce.length) - 1) & 0x7;
+        
+        System.arraycopy(nonce, 0, b0, 1, nonce.length);
+        
+        int q = dataLen;
+        int count = 1;
+        while (q > 0)
+        {
+            b0[b0.length - count] = (byte)(q & 0xff);
+            q >>>= 8;
+            count++;
+        }
+        
+        cMac.update(b0, 0, b0.length);
+        
+        //
+        // process associated text
+        //
+        if (associatedText != null)
+        {
+            int extra;
+            
+            if (associatedText.length < ((1 << 16) - (1 << 8)))
+            {
+                cMac.update((byte)(associatedText.length >> 8));
+                cMac.update((byte)associatedText.length);
+                
+                extra = 2;
+            }
+            else // can't go any higher than 2^32
+            {
+                cMac.update((byte)0xff);
+                cMac.update((byte)0xfe);
+                cMac.update((byte)(associatedText.length >> 24));
+                cMac.update((byte)(associatedText.length >> 16));
+                cMac.update((byte)(associatedText.length >> 8));
+                cMac.update((byte)associatedText.length);
+                
+                extra = 6;
+            }
+            
+            cMac.update(associatedText, 0, associatedText.length);
+            
+            extra = (extra + associatedText.length) % 16;
+            if (extra != 0)
+            {
+                for (int i = 0; i != 16 - extra; i++)
+                {
+                    cMac.update((byte)0x00);
+                }
+            }
+        }
+        
+        //
+        // add the text
+        //
+        cMac.update(data, dataOff, dataLen);
+
+        return cMac.doFinal(macBlock, 0);
+    }
+    
+    /**
+     * compare two byte arrays.
+     */
+    private boolean areEqual(
+        byte[]    a,
+        byte[]    b)
+    {
+        if (a.length != b.length)
+        {
+            return false;
+        }
+        
+        for (int i = 0; i != b.length; i++)
+        {
+            if (a[i] != b[i])
+            {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java b/libcore/security/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java
new file mode 100644
index 0000000..0f64f04
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java
@@ -0,0 +1,250 @@
+package org.bouncycastle.crypto.modes;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
+ */
+public class CFBBlockCipher
+    implements BlockCipher
+{
+    private byte[]          IV;
+    private byte[]          cfbV;
+    private byte[]          cfbOutV;
+
+    private int             blockSize;
+    private BlockCipher     cipher = null;
+    private boolean         encrypting;
+
+    /**
+     * Basic constructor.
+     *
+     * @param cipher the block cipher to be used as the basis of the
+     * feedback mode.
+     * @param bitBlockSize the block size in bits (note: a multiple of 8)
+     */
+    public CFBBlockCipher(
+        BlockCipher cipher,
+        int         bitBlockSize)
+    {
+        this.cipher = cipher;
+        this.blockSize = bitBlockSize / 8;
+
+        this.IV = new byte[cipher.getBlockSize()];
+        this.cfbV = new byte[cipher.getBlockSize()];
+        this.cfbOutV = new byte[cipher.getBlockSize()];
+    }
+
+    /**
+     * return the underlying block cipher that we are wrapping.
+     *
+     * @return the underlying block cipher that we are wrapping.
+     */
+    public BlockCipher getUnderlyingCipher()
+    {
+        return cipher;
+    }
+
+    /**
+     * Initialise the cipher and, possibly, the initialisation vector (IV).
+     * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+     * An IV which is too short is handled in FIPS compliant fashion.
+     *
+     * @param encrypting if true the cipher is initialised for
+     *  encryption, if false for decryption.
+     * @param params the key and other data required by the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean             encrypting,
+        CipherParameters    params)
+        throws IllegalArgumentException
+    {
+        this.encrypting = encrypting;
+        
+        if (params instanceof ParametersWithIV)
+        {
+                ParametersWithIV ivParam = (ParametersWithIV)params;
+                byte[]      iv = ivParam.getIV();
+
+                if (iv.length < IV.length)
+                {
+                    // prepend the supplied IV with zeros (per FIPS PUB 81)
+                    System.arraycopy(iv, 0, IV, IV.length - iv.length, iv.length);
+                    for (int i = 0; i < IV.length - iv.length; i++)
+                    {
+                        IV[i] = 0;
+                    }
+                }
+                else
+                {
+                    System.arraycopy(iv, 0, IV, 0, IV.length);
+                }
+
+                reset();
+
+                cipher.init(true, ivParam.getParameters());
+        }
+        else
+        {
+                reset();
+
+                cipher.init(true, params);
+        }
+    }
+
+    /**
+     * return the algorithm name and mode.
+     *
+     * @return the name of the underlying algorithm followed by "/CFB"
+     * and the block size in bits.
+     */
+    public String getAlgorithmName()
+    {
+        return cipher.getAlgorithmName() + "/CFB" + (blockSize * 8);
+    }
+
+    /**
+     * return the block size we are operating at.
+     *
+     * @return the block size we are operating at (in bytes).
+     */
+    public int getBlockSize()
+    {
+        return blockSize;
+    }
+
+    /**
+     * Process one block of input from the array in and write it to
+     * the out array.
+     *
+     * @param in the array containing the input data.
+     * @param inOff offset into the in array the data starts at.
+     * @param out the array the output data will be copied into.
+     * @param outOff the offset into the out array the output will start at.
+     * @exception DataLengthException if there isn't enough data in in, or
+     * space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     * @return the number of bytes processed and produced.
+     */
+    public int processBlock(
+        byte[]      in,
+        int         inOff,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        return (encrypting) ? encryptBlock(in, inOff, out, outOff) : decryptBlock(in, inOff, out, outOff);
+    }
+
+    /**
+     * Do the appropriate processing for CFB mode encryption.
+     *
+     * @param in the array containing the data to be encrypted.
+     * @param inOff offset into the in array the data starts at.
+     * @param out the array the encrypted data will be copied into.
+     * @param outOff the offset into the out array the output will start at.
+     * @exception DataLengthException if there isn't enough data in in, or
+     * space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     * @return the number of bytes processed and produced.
+     */
+    public int encryptBlock(
+        byte[]      in,
+        int         inOff,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        if ((inOff + blockSize) > in.length)
+        {
+            throw new DataLengthException("input buffer too short");
+        }
+
+        if ((outOff + blockSize) > out.length)
+        {
+            throw new DataLengthException("output buffer too short");
+        }
+
+        cipher.processBlock(cfbV, 0, cfbOutV, 0);
+
+        //
+        // XOR the cfbV with the plaintext producing the cipher text
+        //
+        for (int i = 0; i < blockSize; i++)
+        {
+            out[outOff + i] = (byte)(cfbOutV[i] ^ in[inOff + i]);
+        }
+
+        //
+        // change over the input block.
+        //
+        System.arraycopy(cfbV, blockSize, cfbV, 0, cfbV.length - blockSize);
+        System.arraycopy(out, outOff, cfbV, cfbV.length - blockSize, blockSize);
+
+        return blockSize;
+    }
+
+    /**
+     * Do the appropriate processing for CFB mode decryption.
+     *
+     * @param in the array containing the data to be decrypted.
+     * @param inOff offset into the in array the data starts at.
+     * @param out the array the encrypted data will be copied into.
+     * @param outOff the offset into the out array the output will start at.
+     * @exception DataLengthException if there isn't enough data in in, or
+     * space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     * @return the number of bytes processed and produced.
+     */
+    public int decryptBlock(
+        byte[]      in,
+        int         inOff,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        if ((inOff + blockSize) > in.length)
+        {
+            throw new DataLengthException("input buffer too short");
+        }
+
+        if ((outOff + blockSize) > out.length)
+        {
+            throw new DataLengthException("output buffer too short");
+        }
+
+        cipher.processBlock(cfbV, 0, cfbOutV, 0);
+
+        //
+        // change over the input block.
+        //
+        System.arraycopy(cfbV, blockSize, cfbV, 0, cfbV.length - blockSize);
+        System.arraycopy(in, inOff, cfbV, cfbV.length - blockSize, blockSize);
+
+        //
+        // XOR the cfbV with the plaintext producing the plain text
+        //
+        for (int i = 0; i < blockSize; i++)
+        {
+            out[outOff + i] = (byte)(cfbOutV[i] ^ in[inOff + i]);
+        }
+
+        return blockSize;
+    }
+
+    /**
+     * reset the chaining vector back to the IV and reset the underlying
+     * cipher.
+     */
+    public void reset()
+    {
+        System.arraycopy(IV, 0, cfbV, 0, IV.length);
+
+        cipher.reset();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java b/libcore/security/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java
new file mode 100644
index 0000000..b8e5b61
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java
@@ -0,0 +1,265 @@
+package org.bouncycastle.crypto.modes;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.BufferedBlockCipher;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * A Cipher Text Stealing (CTS) mode cipher. CTS allows block ciphers to
+ * be used to produce cipher text which is the same length as the plain text.
+ */
+public class CTSBlockCipher
+    extends BufferedBlockCipher
+{
+    private int     blockSize;
+
+    /**
+     * Create a buffered block cipher that uses Cipher Text Stealing
+     *
+     * @param cipher the underlying block cipher this buffering object wraps.
+     */
+    public CTSBlockCipher(
+        BlockCipher     cipher)
+    {
+        if ((cipher instanceof OFBBlockCipher) || (cipher instanceof CFBBlockCipher))
+        {
+            throw new IllegalArgumentException("CTSBlockCipher can only accept ECB, or CBC ciphers");
+        }
+
+        this.cipher = cipher;
+
+        blockSize = cipher.getBlockSize();
+
+        buf = new byte[blockSize * 2];
+        bufOff = 0;
+    }
+
+    /**
+     * return the size of the output buffer required for an update 
+     * an input of len bytes.
+     *
+     * @param len the length of the input.
+     * @return the space required to accommodate a call to update
+     * with len bytes of input.
+     */
+    public int getUpdateOutputSize(
+        int len)
+    {
+        int total       = len + bufOff;
+        int leftOver    = total % buf.length;
+
+        if (leftOver == 0)
+        {
+            return total - buf.length;
+        }
+
+        return total - leftOver;
+    }
+
+    /**
+     * return the size of the output buffer required for an update plus a
+     * doFinal with an input of len bytes.
+     *
+     * @param len the length of the input.
+     * @return the space required to accommodate a call to update and doFinal
+     * with len bytes of input.
+     */
+    public int getOutputSize(
+        int len)
+    {
+        return len + bufOff;
+    }
+
+    /**
+     * process a single byte, producing an output block if neccessary.
+     *
+     * @param in the input byte.
+     * @param out the space for any output that might be produced.
+     * @param outOff the offset from which the output will be copied.
+     * @return the number of output bytes copied to out.
+     * @exception DataLengthException if there isn't enough space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     */
+    public int processByte(
+        byte        in,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        int         resultLen = 0;
+
+        if (bufOff == buf.length)
+        {
+            resultLen = cipher.processBlock(buf, 0, out, outOff);
+            System.arraycopy(buf, blockSize, buf, 0, blockSize);
+
+            bufOff = blockSize;
+        }
+
+        buf[bufOff++] = in;
+
+        return resultLen;
+    }
+
+    /**
+     * process an array of bytes, producing output if necessary.
+     *
+     * @param in the input byte array.
+     * @param inOff the offset at which the input data starts.
+     * @param len the number of bytes to be copied out of the input array.
+     * @param out the space for any output that might be produced.
+     * @param outOff the offset from which the output will be copied.
+     * @return the number of output bytes copied to out.
+     * @exception DataLengthException if there isn't enough space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     */
+    public int processBytes(
+        byte[]      in,
+        int         inOff,
+        int         len,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        if (len < 0)
+        {
+            throw new IllegalArgumentException("Can't have a negative input length!");
+        }
+
+        int blockSize   = getBlockSize();
+        int length      = getUpdateOutputSize(len);
+        
+        if (length > 0)
+        {
+            if ((outOff + length) > out.length)
+            {
+                throw new DataLengthException("output buffer too short");
+            }
+        }
+
+        int resultLen = 0;
+        int gapLen = buf.length - bufOff;
+
+        if (len > gapLen)
+        {
+            System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+            resultLen += cipher.processBlock(buf, 0, out, outOff);
+            System.arraycopy(buf, blockSize, buf, 0, blockSize);
+
+            bufOff = blockSize;
+
+            len -= gapLen;
+            inOff += gapLen;
+
+            while (len > blockSize)
+            {
+                System.arraycopy(in, inOff, buf, bufOff, blockSize);
+                resultLen += cipher.processBlock(buf, 0, out, outOff + resultLen);
+                System.arraycopy(buf, blockSize, buf, 0, blockSize);
+
+                len -= blockSize;
+                inOff += blockSize;
+            }
+        }
+
+        System.arraycopy(in, inOff, buf, bufOff, len);
+
+        bufOff += len;
+
+        return resultLen;
+    }
+
+    /**
+     * Process the last block in the buffer.
+     *
+     * @param out the array the block currently being held is copied into.
+     * @param outOff the offset at which the copying starts.
+     * @return the number of output bytes copied to out.
+     * @exception DataLengthException if there is insufficient space in out for
+     * the output.
+     * @exception IllegalStateException if the underlying cipher is not
+     * initialised.
+     * @exception InvalidCipherTextException if cipher text decrypts wrongly (in
+     * case the exception will never get thrown).
+     */
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+        throws DataLengthException, IllegalStateException, InvalidCipherTextException
+    {
+        if (bufOff + outOff > out.length)
+        {
+            throw new DataLengthException("output buffer to small in doFinal");
+        }
+
+        int     blockSize = cipher.getBlockSize();
+        int     len = bufOff - blockSize;
+        byte[]  block = new byte[blockSize];
+
+        if (forEncryption)
+        {
+            cipher.processBlock(buf, 0, block, 0);
+            
+            if (bufOff < blockSize)
+            {
+                throw new DataLengthException("need at least one block of input for CTS");
+            }
+
+            for (int i = bufOff; i != buf.length; i++)
+            {
+                buf[i] = block[i - blockSize];
+            }
+
+            for (int i = blockSize; i != bufOff; i++)
+            {
+                buf[i] ^= block[i - blockSize];
+            }
+
+            if (cipher instanceof CBCBlockCipher)
+            {
+                BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher();
+
+                c.processBlock(buf, blockSize, out, outOff);
+            }
+            else
+            {
+                cipher.processBlock(buf, blockSize, out, outOff);
+            }
+
+            System.arraycopy(block, 0, out, outOff + blockSize, len);
+        }
+        else
+        {
+            byte[]  lastBlock = new byte[blockSize];
+
+            if (cipher instanceof CBCBlockCipher)
+            {
+                BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher();
+
+                c.processBlock(buf, 0, block, 0);
+            }
+            else
+            {
+                cipher.processBlock(buf, 0, block, 0);
+            }
+
+            for (int i = blockSize; i != bufOff; i++)
+            {
+                lastBlock[i - blockSize] = (byte)(block[i - blockSize] ^ buf[i]);
+            }
+
+            System.arraycopy(buf, blockSize, block, 0, len);
+
+            cipher.processBlock(block, 0, out, outOff);
+            System.arraycopy(lastBlock, 0, out, outOff + blockSize, len);
+        }
+
+        int offset = bufOff;
+
+        reset();
+
+        return offset;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/modes/GOFBBlockCipher.java b/libcore/security/src/main/java/org/bouncycastle/crypto/modes/GOFBBlockCipher.java
new file mode 100644
index 0000000..007bffc
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/modes/GOFBBlockCipher.java
@@ -0,0 +1,226 @@
+package org.bouncycastle.crypto.modes;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * implements the GOST 28147 OFB counter mode (GCTR).
+ */
+public class GOFBBlockCipher
+    implements BlockCipher
+{
+    private byte[]          IV;
+    private byte[]          ofbV;
+    private byte[]          ofbOutV;
+
+    private final int             blockSize;
+    private final BlockCipher     cipher;
+
+    boolean firstStep = true;
+    int N3;
+    int N4;
+    static final int C1 = 16843012; //00000001000000010000000100000100
+    static final int C2 = 16843009; //00000001000000010000000100000001
+
+
+    /**
+     * Basic constructor.
+     *
+     * @param cipher the block cipher to be used as the basis of the
+     * counter mode (must have a 64 bit block size).
+     */
+    public GOFBBlockCipher(
+        BlockCipher cipher)
+    {
+        this.cipher = cipher;
+        this.blockSize = cipher.getBlockSize();
+        
+        if (blockSize != 8)
+        {
+            throw new IllegalArgumentException("GTCR only for 64 bit block ciphers");
+        }
+
+        this.IV = new byte[cipher.getBlockSize()];
+        this.ofbV = new byte[cipher.getBlockSize()];
+        this.ofbOutV = new byte[cipher.getBlockSize()];
+    }
+
+    /**
+     * return the underlying block cipher that we are wrapping.
+     *
+     * @return the underlying block cipher that we are wrapping.
+     */
+    public BlockCipher getUnderlyingCipher()
+    {
+        return cipher;
+    }
+
+    /**
+     * Initialise the cipher and, possibly, the initialisation vector (IV).
+     * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+     * An IV which is too short is handled in FIPS compliant fashion.
+     *
+     * @param encrypting if true the cipher is initialised for
+     *  encryption, if false for decryption.
+     * @param params the key and other data required by the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean             encrypting, //ignored by this CTR mode
+        CipherParameters    params)
+        throws IllegalArgumentException
+    {
+        firstStep = true;
+        N3 = 0;
+        N4 = 0;
+
+        if (params instanceof ParametersWithIV)
+        {
+                ParametersWithIV ivParam = (ParametersWithIV)params;
+                byte[]      iv = ivParam.getIV();
+
+                if (iv.length < IV.length)
+                {
+                    // prepend the supplied IV with zeros (per FIPS PUB 81)
+                    System.arraycopy(iv, 0, IV, IV.length - iv.length, iv.length); 
+                    for (int i = 0; i < IV.length - iv.length; i++)
+                    {
+                        IV[i] = 0;
+                    }
+                }
+                else
+                {
+                    System.arraycopy(iv, 0, IV, 0, IV.length);
+                }
+
+                reset();
+
+                cipher.init(true, ivParam.getParameters());
+        }
+        else
+        {
+                reset();
+
+                cipher.init(true, params);
+        }
+    }
+
+    /**
+     * return the algorithm name and mode.
+     *
+     * @return the name of the underlying algorithm followed by "/GCTR"
+     * and the block size in bits
+     */
+    public String getAlgorithmName()
+    {
+        return cipher.getAlgorithmName() + "/GCTR";
+    }
+
+    
+    /**
+     * return the block size we are operating at (in bytes).
+     *
+     * @return the block size we are operating at (in bytes).
+     */
+    public int getBlockSize()
+    {
+        return blockSize;
+    }
+
+    /**
+     * Process one block of input from the array in and write it to
+     * the out array.
+     *
+     * @param in the array containing the input data.
+     * @param inOff offset into the in array the data starts at.
+     * @param out the array the output data will be copied into.
+     * @param outOff the offset into the out array the output will start at.
+     * @exception DataLengthException if there isn't enough data in in, or
+     * space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     * @return the number of bytes processed and produced.
+     */
+    public int processBlock(
+        byte[]      in,
+        int         inOff,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        if ((inOff + blockSize) > in.length)
+        {
+            throw new DataLengthException("input buffer too short");
+        }
+
+        if ((outOff + blockSize) > out.length)
+        {
+            throw new DataLengthException("output buffer too short");
+        }
+
+        if (firstStep)
+        {
+            firstStep = false;
+            cipher.processBlock(ofbV, 0, ofbOutV, 0);
+            N3 = bytesToint(ofbOutV, 0);
+            N4 = bytesToint(ofbOutV, 4);
+        }
+        N3 += C2;
+        N4 += C1;
+        intTobytes(N3, ofbV, 0);
+        intTobytes(N4, ofbV, 4);
+
+        cipher.processBlock(ofbV, 0, ofbOutV, 0);
+
+        //
+        // XOR the ofbV with the plaintext producing the cipher text (and
+        // the next input block).
+        //
+        for (int i = 0; i < blockSize; i++)
+        {
+            out[outOff + i] = (byte)(ofbOutV[i] ^ in[inOff + i]);
+        }
+
+        //
+        // change over the input block.
+        //
+        System.arraycopy(ofbV, blockSize, ofbV, 0, ofbV.length - blockSize);
+        System.arraycopy(ofbOutV, 0, ofbV, ofbV.length - blockSize, blockSize);
+
+        return blockSize;
+    }
+
+    /**
+     * reset the feedback vector back to the IV and reset the underlying
+     * cipher.
+     */
+    public void reset()
+    {
+        System.arraycopy(IV, 0, ofbV, 0, IV.length);
+
+        cipher.reset();
+    }
+
+    //array of bytes to type int
+    private int bytesToint(
+        byte[]  in,
+        int     inOff)
+    {
+        return  ((in[inOff + 3] << 24) & 0xff000000) + ((in[inOff + 2] << 16) & 0xff0000) +
+                ((in[inOff + 1] << 8) & 0xff00) + (in[inOff] & 0xff);
+    }
+
+    //int to array of bytes
+    private void intTobytes(
+            int     num,
+            byte[]  out,
+            int     outOff)
+    {
+            out[outOff + 3] = (byte)(num >>> 24);
+            out[outOff + 2] = (byte)(num >>> 16);
+            out[outOff + 1] = (byte)(num >>> 8);
+            out[outOff] =     (byte)num;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java b/libcore/security/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java
new file mode 100644
index 0000000..f209b9f
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java
@@ -0,0 +1,179 @@
+package org.bouncycastle.crypto.modes;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * implements a Output-FeedBack (OFB) mode on top of a simple cipher.
+ */
+public class OFBBlockCipher
+    implements BlockCipher
+{
+    private byte[]          IV;
+    private byte[]          ofbV;
+    private byte[]          ofbOutV;
+
+    private final int             blockSize;
+    private final BlockCipher     cipher;
+
+    /**
+     * Basic constructor.
+     *
+     * @param cipher the block cipher to be used as the basis of the
+     * feedback mode.
+     * @param blockSize the block size in bits (note: a multiple of 8)
+     */
+    public OFBBlockCipher(
+        BlockCipher cipher,
+        int         blockSize)
+    {
+        this.cipher = cipher;
+        this.blockSize = blockSize / 8;
+
+        this.IV = new byte[cipher.getBlockSize()];
+        this.ofbV = new byte[cipher.getBlockSize()];
+        this.ofbOutV = new byte[cipher.getBlockSize()];
+    }
+
+    /**
+     * return the underlying block cipher that we are wrapping.
+     *
+     * @return the underlying block cipher that we are wrapping.
+     */
+    public BlockCipher getUnderlyingCipher()
+    {
+        return cipher;
+    }
+
+    /**
+     * Initialise the cipher and, possibly, the initialisation vector (IV).
+     * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+     * An IV which is too short is handled in FIPS compliant fashion.
+     *
+     * @param encrypting if true the cipher is initialised for
+     *  encryption, if false for decryption.
+     * @param params the key and other data required by the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean             encrypting, //ignored by this OFB mode
+        CipherParameters    params)
+        throws IllegalArgumentException
+    {
+        if (params instanceof ParametersWithIV)
+        {
+                ParametersWithIV ivParam = (ParametersWithIV)params;
+                byte[]      iv = ivParam.getIV();
+
+                if (iv.length < IV.length)
+                {
+                    // prepend the supplied IV with zeros (per FIPS PUB 81)
+                    System.arraycopy(iv, 0, IV, IV.length - iv.length, iv.length); 
+                    for (int i = 0; i < IV.length - iv.length; i++)
+                    {
+                        IV[i] = 0;
+                    }
+                }
+                else
+                {
+                    System.arraycopy(iv, 0, IV, 0, IV.length);
+                }
+
+                reset();
+
+                cipher.init(true, ivParam.getParameters());
+        }
+        else
+        {
+                reset();
+
+                cipher.init(true, params);
+        }
+    }
+
+    /**
+     * return the algorithm name and mode.
+     *
+     * @return the name of the underlying algorithm followed by "/OFB"
+     * and the block size in bits
+     */
+    public String getAlgorithmName()
+    {
+        return cipher.getAlgorithmName() + "/OFB" + (blockSize * 8);
+    }
+
+    
+    /**
+     * return the block size we are operating at (in bytes).
+     *
+     * @return the block size we are operating at (in bytes).
+     */
+    public int getBlockSize()
+    {
+        return blockSize;
+    }
+
+    /**
+     * Process one block of input from the array in and write it to
+     * the out array.
+     *
+     * @param in the array containing the input data.
+     * @param inOff offset into the in array the data starts at.
+     * @param out the array the output data will be copied into.
+     * @param outOff the offset into the out array the output will start at.
+     * @exception DataLengthException if there isn't enough data in in, or
+     * space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     * @return the number of bytes processed and produced.
+     */
+    public int processBlock(
+        byte[]      in,
+        int         inOff,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        if ((inOff + blockSize) > in.length)
+        {
+            throw new DataLengthException("input buffer too short");
+        }
+
+        if ((outOff + blockSize) > out.length)
+        {
+            throw new DataLengthException("output buffer too short");
+        }
+
+        cipher.processBlock(ofbV, 0, ofbOutV, 0);
+
+        //
+        // XOR the ofbV with the plaintext producing the cipher text (and
+        // the next input block).
+        //
+        for (int i = 0; i < blockSize; i++)
+        {
+            out[outOff + i] = (byte)(ofbOutV[i] ^ in[inOff + i]);
+        }
+
+        //
+        // change over the input block.
+        //
+        System.arraycopy(ofbV, blockSize, ofbV, 0, ofbV.length - blockSize);
+        System.arraycopy(ofbOutV, 0, ofbV, ofbV.length - blockSize, blockSize);
+
+        return blockSize;
+    }
+
+    /**
+     * reset the feedback vector back to the IV and reset the underlying
+     * cipher.
+     */
+    public void reset()
+    {
+        System.arraycopy(IV, 0, ofbV, 0, IV.length);
+
+        cipher.reset();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/modes/PaddedBlockCipher.java b/libcore/security/src/main/java/org/bouncycastle/crypto/modes/PaddedBlockCipher.java
new file mode 100644
index 0000000..f15ed67
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/modes/PaddedBlockCipher.java
@@ -0,0 +1,253 @@
+package org.bouncycastle.crypto.modes;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.BufferedBlockCipher;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * A wrapper class that allows block ciphers to be used to process data in
+ * a piecemeal fashion with PKCS5/PKCS7 padding. The PaddedBlockCipher
+ * outputs a block only when the buffer is full and more data is being added,
+ * or on a doFinal (unless the current block in the buffer is a pad block).
+ * The padding mechanism used is the one outlined in PKCS5/PKCS7.
+ *
+ * @deprecated use org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher instead.
+ */
+public class PaddedBlockCipher
+    extends BufferedBlockCipher
+{
+    /**
+     * Create a buffered block cipher with, or without, padding.
+     *
+     * @param cipher the underlying block cipher this buffering object wraps.
+     */
+    public PaddedBlockCipher(
+        BlockCipher     cipher)
+    {
+        this.cipher = cipher;
+
+        buf = new byte[cipher.getBlockSize()];
+        bufOff = 0;
+    }
+
+    /**
+     * return the size of the output buffer required for an update plus a
+     * doFinal with an input of len bytes.
+     *
+     * @param len the length of the input.
+     * @return the space required to accommodate a call to update and doFinal
+     * with len bytes of input.
+     */
+    public int getOutputSize(
+        int len)
+    {
+        int total       = len + bufOff;
+        int leftOver    = total % buf.length;
+
+        if (leftOver == 0)
+        {
+            if (forEncryption)
+            {
+                return total + buf.length;
+            }
+
+            return total;
+        }
+
+        return total - leftOver + buf.length;
+    }
+
+    /**
+     * return the size of the output buffer required for an update 
+     * an input of len bytes.
+     *
+     * @param len the length of the input.
+     * @return the space required to accommodate a call to update
+     * with len bytes of input.
+     */
+    public int getUpdateOutputSize(
+        int len)
+    {
+        int total       = len + bufOff;
+        int leftOver    = total % buf.length;
+
+        if (leftOver == 0)
+        {
+            return total - buf.length;
+        }
+
+        return total - leftOver;
+    }
+
+    /**
+     * process a single byte, producing an output block if neccessary.
+     *
+     * @param in the input byte.
+     * @param out the space for any output that might be produced.
+     * @param outOff the offset from which the output will be copied.
+     * @exception DataLengthException if there isn't enough space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     */
+    public int processByte(
+        byte        in,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        int         resultLen = 0;
+
+        if (bufOff == buf.length)
+        {
+            resultLen = cipher.processBlock(buf, 0, out, outOff);
+            bufOff = 0;
+        }
+
+        buf[bufOff++] = in;
+
+        return resultLen;
+    }
+
+    /**
+     * process an array of bytes, producing output if necessary.
+     *
+     * @param in the input byte array.
+     * @param inOff the offset at which the input data starts.
+     * @param len the number of bytes to be copied out of the input array.
+     * @param out the space for any output that might be produced.
+     * @param outOff the offset from which the output will be copied.
+     * @exception DataLengthException if there isn't enough space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     */
+    public int processBytes(
+        byte[]      in,
+        int         inOff,
+        int         len,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        if (len < 0)
+        {
+            throw new IllegalArgumentException("Can't have a negative input length!");
+        }
+
+        int blockSize   = getBlockSize();
+        int length      = getUpdateOutputSize(len);
+        
+        if (length > 0)
+        {
+            if ((outOff + length) > out.length)
+            {
+                throw new DataLengthException("output buffer too short");
+            }
+        }
+
+        int resultLen = 0;
+        int gapLen = buf.length - bufOff;
+
+        if (len > gapLen)
+        {
+            System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+            resultLen += cipher.processBlock(buf, 0, out, outOff);
+
+            bufOff = 0;
+            len -= gapLen;
+            inOff += gapLen;
+
+            while (len > buf.length)
+            {
+                resultLen += cipher.processBlock(in, inOff, out, outOff + resultLen);
+
+                len -= blockSize;
+                inOff += blockSize;
+            }
+        }
+
+        System.arraycopy(in, inOff, buf, bufOff, len);
+
+        bufOff += len;
+
+        return resultLen;
+    }
+
+    /**
+     * Process the last block in the buffer. If the buffer is currently
+     * full and padding needs to be added a call to doFinal will produce
+     * 2 * getBlockSize() bytes.
+     *
+     * @param out the array the block currently being held is copied into.
+     * @param outOff the offset at which the copying starts.
+     * @exception DataLengthException if there is insufficient space in out for
+     * the output or we are decrypting and the input is not block size aligned.
+     * @exception IllegalStateException if the underlying cipher is not
+     * initialised.
+     * @exception InvalidCipherTextException if padding is expected and not found.
+     */
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+        throws DataLengthException, IllegalStateException, InvalidCipherTextException
+    {
+        int blockSize = cipher.getBlockSize();
+        int resultLen = 0;
+
+        if (forEncryption)
+        {
+            if (bufOff == blockSize)
+            {
+                if ((outOff + 2 * blockSize) > out.length)
+                {
+                    throw new DataLengthException("output buffer too short");
+                }
+
+                resultLen = cipher.processBlock(buf, 0, out, outOff);
+                bufOff = 0;
+            }
+
+            //
+            // add PKCS7 padding
+            //
+            byte code = (byte)(blockSize - bufOff);
+
+            while (bufOff < blockSize)
+            {
+                buf[bufOff] = code;
+                bufOff++;
+            }
+
+            resultLen += cipher.processBlock(buf, 0, out, outOff + resultLen);
+        }
+        else
+        {
+            if (bufOff == blockSize)
+            {
+                resultLen = cipher.processBlock(buf, 0, buf, 0);
+                bufOff = 0;
+            }
+            else
+            {
+                throw new DataLengthException("last block incomplete in decryption");
+            }
+
+            //
+            // remove PKCS7 padding
+            //
+            int count = buf[blockSize - 1] & 0xff;
+
+            if ((count < 0) || (count > blockSize))
+            {
+                throw new InvalidCipherTextException("pad block corrupted");
+            }
+
+            resultLen -= count;
+
+            System.arraycopy(buf, 0, out, outOff, resultLen);
+        }
+
+        reset();
+
+        return resultLen;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java b/libcore/security/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java
new file mode 100644
index 0000000..ce0b865
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java
@@ -0,0 +1,115 @@
+package org.bouncycastle.crypto.modes;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * Implements the Segmented Integer Counter (SIC) mode on top of a simple
+ * block cipher. This mode is also known as CTR mode.
+ */
+public class SICBlockCipher implements BlockCipher
+{
+    private final BlockCipher     cipher;
+    private final int             blockSize;
+    
+    private byte[]          IV;
+    private byte[]          counter;
+    private byte[]          counterOut;
+
+
+    /**
+     * Basic constructor.
+     *
+     * @param c the block cipher to be used.
+     */
+    public SICBlockCipher(BlockCipher c)
+    {
+        this.cipher = c;
+        this.blockSize = cipher.getBlockSize();
+        this.IV = new byte[blockSize];
+        this.counter = new byte[blockSize];
+        this.counterOut = new byte[blockSize];
+    }
+
+
+    /**
+     * return the underlying block cipher that we are wrapping.
+     *
+     * @return the underlying block cipher that we are wrapping.
+     */
+    public BlockCipher getUnderlyingCipher()
+    {
+        return cipher;
+    }
+
+
+    public void init(
+        boolean             forEncryption, //ignored by this CTR mode
+        CipherParameters    params)
+        throws IllegalArgumentException
+    {
+        if (params instanceof ParametersWithIV)
+        {
+          ParametersWithIV ivParam = (ParametersWithIV)params;
+          byte[]           iv      = ivParam.getIV();
+          System.arraycopy(iv, 0, IV, 0, IV.length);
+
+          reset();
+          cipher.init(true, ivParam.getParameters());
+        }
+    }
+
+    public String getAlgorithmName()
+    {
+        return cipher.getAlgorithmName() + "/SIC";
+    }
+
+    public int getBlockSize()
+    {
+        return cipher.getBlockSize();
+    }
+
+
+    public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
+          throws DataLengthException, IllegalStateException
+    {
+        cipher.processBlock(counter, 0, counterOut, 0);
+
+        //
+        // XOR the counterOut with the plaintext producing the cipher text
+        //
+        for (int i = 0; i < counterOut.length; i++)
+        {
+          out[outOff + i] = (byte)(counterOut[i] ^ in[inOff + i]);
+        }
+
+        int    carry = 1;
+        
+        for (int i = counter.length - 1; i >= 0; i--)
+        {
+            int    x = (counter[i] & 0xff) + carry;
+            
+            if (x > 0xff)
+            {
+                carry = 1;
+            }
+            else
+            {
+                carry = 0;
+            }
+            
+            counter[i] = (byte)x;
+        }
+
+        return counter.length;
+    }
+
+
+    public void reset()
+    {
+        System.arraycopy(IV, 0, counter, 0, counter.length);
+        cipher.reset();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/BlockCipherPadding.java b/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/BlockCipherPadding.java
new file mode 100644
index 0000000..7c4f0ae
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/BlockCipherPadding.java
@@ -0,0 +1,48 @@
+package org.bouncycastle.crypto.paddings;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * Block cipher padders are expected to conform to this interface
+ */
+public interface BlockCipherPadding
+{
+    /**
+     * Initialise the padder.
+     *
+     * @param random the source of randomness for the padding, if required.
+     */
+    public void init(SecureRandom random)
+        throws IllegalArgumentException;
+
+    /**
+     * Return the name of the algorithm the cipher implements.
+     *
+     * @return the name of the algorithm the cipher implements.
+     */
+    public String getPaddingName();
+
+    /**
+     * add the pad bytes to the passed in block, returning the
+     * number of bytes added.
+     * <p>
+     * Note: this assumes that the last block of plain text is always 
+     * passed to it inside in. i.e. if inOff is zero, indicating the
+     * entire block is to be overwritten with padding the value of in
+     * should be the same as the last block of plain text. The reason
+     * for this is that some modes such as "trailing bit compliment"
+     * base the padding on the last byte of plain text.
+     * </p>
+     */
+    public int addPadding(byte[] in, int inOff);
+
+    /**
+     * return the number of pad bytes present in the block.
+     * @exception InvalidCipherTextException if the padding is badly formed
+     * or invalid.
+     */
+    public int padCount(byte[] in)
+        throws InvalidCipherTextException;
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/ISO10126d2Padding.java b/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/ISO10126d2Padding.java
new file mode 100644
index 0000000..63e29d8
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/ISO10126d2Padding.java
@@ -0,0 +1,79 @@
+package org.bouncycastle.crypto.paddings;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * A padder that adds ISO10126-2 padding to a block.
+ */
+public class ISO10126d2Padding
+    implements BlockCipherPadding
+{
+    SecureRandom    random;
+
+    /**
+     * Initialise the padder.
+     *
+     * @param random a SecureRandom if available.
+     */
+    public void init(SecureRandom random)
+        throws IllegalArgumentException
+    {
+        if (random != null)
+        {
+            this.random = random;
+        }
+        else
+        {
+            this.random = new SecureRandom();
+        }
+    }
+
+    /**
+     * Return the name of the algorithm the padder implements.
+     *
+     * @return the name of the algorithm the padder implements.
+     */
+    public String getPaddingName()
+    {
+        return "ISO10126-2";
+    }
+
+    /**
+     * add the pad bytes to the passed in block, returning the
+     * number of bytes added.
+     */
+    public int addPadding(
+        byte[]  in,
+        int     inOff)
+    {
+        byte code = (byte)(in.length - inOff);
+
+        while (inOff < (in.length - 1))
+        {
+            in[inOff] = (byte)random.nextInt();
+            inOff++;
+        }
+
+        in[inOff] = code;
+
+        return code;
+    }
+
+    /**
+     * return the number of pad bytes present in the block.
+     */
+    public int padCount(byte[] in)
+        throws InvalidCipherTextException
+    {
+        int count = in[in.length - 1] & 0xff;
+
+        if (count > in.length)
+        {
+            throw new InvalidCipherTextException("pad block corrupted");
+        }
+
+        return count;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/ISO7816d4Padding.java b/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/ISO7816d4Padding.java
new file mode 100644
index 0000000..54c31a9
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/ISO7816d4Padding.java
@@ -0,0 +1,77 @@
+package org.bouncycastle.crypto.paddings;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * A padder that adds the padding according to the scheme referenced in
+ * ISO 7814-4 - scheme 2 from ISO 9797-1. The first byte is 0x80, rest is 0x00
+ */
+public class ISO7816d4Padding
+    implements BlockCipherPadding
+{
+    /**
+     * Initialise the padder.
+     *
+     * @param random - a SecureRandom if available.
+     */
+    public void init(SecureRandom random)
+        throws IllegalArgumentException
+    {
+        // nothing to do.
+    }
+
+    /**
+     * Return the name of the algorithm the padder implements.
+     *
+     * @return the name of the algorithm the padder implements.
+     */
+    public String getPaddingName()
+    {
+        return "ISO7816-4";
+    }
+
+    /**
+     * add the pad bytes to the passed in block, returning the
+     * number of bytes added.
+     */
+    public int addPadding(
+        byte[]  in,
+        int     inOff)
+    {
+        int added = (in.length - inOff);
+
+        in [inOff]= (byte) 0x80;
+        inOff ++;
+        
+        while (inOff < in.length)
+        {
+            in[inOff] = (byte) 0;
+            inOff++;
+        }
+
+        return added;
+    }
+
+    /**
+     * return the number of pad bytes present in the block.
+     */
+    public int padCount(byte[] in)
+        throws InvalidCipherTextException
+    {
+        int count = in.length - 1;
+
+        while (count > 0 && in[count] == 0)
+        {
+            count--;
+        }
+
+        if (in[count] != (byte)0x80)
+        {
+            throw new InvalidCipherTextException("pad block corrupted");
+        }
+        
+        return in.length - count;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/PKCS7Padding.java b/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/PKCS7Padding.java
new file mode 100644
index 0000000..c005ff8
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/PKCS7Padding.java
@@ -0,0 +1,76 @@
+package org.bouncycastle.crypto.paddings;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * A padder that adds PKCS7/PKCS5 padding to a block.
+ */
+public class PKCS7Padding
+    implements BlockCipherPadding
+{
+    /**
+     * Initialise the padder.
+     *
+     * @param random - a SecureRandom if available.
+     */
+    public void init(SecureRandom random)
+        throws IllegalArgumentException
+    {
+        // nothing to do.
+    }
+
+    /**
+     * Return the name of the algorithm the padder implements.
+     *
+     * @return the name of the algorithm the padder implements.
+     */
+    public String getPaddingName()
+    {
+        return "PKCS7";
+    }
+
+    /**
+     * add the pad bytes to the passed in block, returning the
+     * number of bytes added.
+     */
+    public int addPadding(
+        byte[]  in,
+        int     inOff)
+    {
+        byte code = (byte)(in.length - inOff);
+
+        while (inOff < in.length)
+        {
+            in[inOff] = code;
+            inOff++;
+        }
+
+        return code;
+    }
+
+    /**
+     * return the number of pad bytes present in the block.
+     */
+    public int padCount(byte[] in)
+        throws InvalidCipherTextException
+    {
+        int count = in[in.length - 1] & 0xff;
+
+        if (count > in.length)
+        {
+            throw new InvalidCipherTextException("pad block corrupted");
+        }
+        
+        for (int i = 1; i <= count; i++)
+        {
+            if (in[in.length - i] != count)
+            {
+                throw new InvalidCipherTextException("pad block corrupted");
+            }
+        }
+
+        return count;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java b/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java
new file mode 100644
index 0000000..ec412b9
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java
@@ -0,0 +1,298 @@
+package org.bouncycastle.crypto.paddings;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.BufferedBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+
+/**
+ * A wrapper class that allows block ciphers to be used to process data in
+ * a piecemeal fashion with padding. The PaddedBufferedBlockCipher
+ * outputs a block only when the buffer is full and more data is being added,
+ * or on a doFinal (unless the current block in the buffer is a pad block).
+ * The default padding mechanism used is the one outlined in PKCS5/PKCS7.
+ */
+public class PaddedBufferedBlockCipher
+    extends BufferedBlockCipher
+{
+    BlockCipherPadding  padding;
+
+    /**
+     * Create a buffered block cipher with the desired padding.
+     *
+     * @param cipher the underlying block cipher this buffering object wraps.
+     * @param padding the padding type.
+     */
+    public PaddedBufferedBlockCipher(
+        BlockCipher         cipher,
+        BlockCipherPadding  padding)
+    {
+        this.cipher = cipher;
+        this.padding = padding;
+
+        buf = new byte[cipher.getBlockSize()];
+        bufOff = 0;
+    }
+
+    /**
+     * Create a buffered block cipher PKCS7 padding
+     *
+     * @param cipher the underlying block cipher this buffering object wraps.
+     */
+    public PaddedBufferedBlockCipher(
+        BlockCipher     cipher)
+    {
+        this(cipher, new PKCS7Padding());
+    }
+
+    /**
+     * initialise the cipher.
+     *
+     * @param forEncryption if true the cipher is initialised for
+     *  encryption, if false for decryption.
+     * @param params the key and other data required by the cipher.
+     * @exception IllegalArgumentException if the params argument is
+     * inappropriate.
+     */
+    public void init(
+        boolean             forEncryption,
+        CipherParameters    params)
+        throws IllegalArgumentException
+    {
+        this.forEncryption = forEncryption;
+
+        reset();
+
+        if (params instanceof ParametersWithRandom)
+        {
+            ParametersWithRandom    p = (ParametersWithRandom)params;
+
+            padding.init(p.getRandom());
+
+            cipher.init(forEncryption, p.getParameters());
+        }
+        else
+        {
+            padding.init(null);
+
+            cipher.init(forEncryption, params);
+        }
+    }
+
+    /**
+     * return the minimum size of the output buffer required for an update
+     * plus a doFinal with an input of len bytes.
+     *
+     * @param len the length of the input.
+     * @return the space required to accommodate a call to update and doFinal
+     * with len bytes of input.
+     */
+    public int getOutputSize(
+        int len)
+    {
+        int total       = len + bufOff;
+        int leftOver    = total % buf.length;
+
+        if (leftOver == 0)
+        {
+            if (forEncryption)
+            {
+                return total + buf.length;
+            }
+
+            return total;
+        }
+
+        return total - leftOver + buf.length;
+    }
+
+    /**
+     * return the size of the output buffer required for an update 
+     * an input of len bytes.
+     *
+     * @param len the length of the input.
+     * @return the space required to accommodate a call to update
+     * with len bytes of input.
+     */
+    public int getUpdateOutputSize(
+        int len)
+    {
+        int total       = len + bufOff;
+        int leftOver    = total % buf.length;
+
+        if (leftOver == 0)
+        {
+            return total - buf.length;
+        }
+
+        return total - leftOver;
+    }
+
+    /**
+     * process a single byte, producing an output block if neccessary.
+     *
+     * @param in the input byte.
+     * @param out the space for any output that might be produced.
+     * @param outOff the offset from which the output will be copied.
+     * @return the number of output bytes copied to out.
+     * @exception DataLengthException if there isn't enough space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     */
+    public int processByte(
+        byte        in,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        int         resultLen = 0;
+
+        if (bufOff == buf.length)
+        {
+            resultLen = cipher.processBlock(buf, 0, out, outOff);
+            bufOff = 0;
+        }
+
+        buf[bufOff++] = in;
+
+        return resultLen;
+    }
+
+    /**
+     * process an array of bytes, producing output if necessary.
+     *
+     * @param in the input byte array.
+     * @param inOff the offset at which the input data starts.
+     * @param len the number of bytes to be copied out of the input array.
+     * @param out the space for any output that might be produced.
+     * @param outOff the offset from which the output will be copied.
+     * @return the number of output bytes copied to out.
+     * @exception DataLengthException if there isn't enough space in out.
+     * @exception IllegalStateException if the cipher isn't initialised.
+     */
+    public int processBytes(
+        byte[]      in,
+        int         inOff,
+        int         len,
+        byte[]      out,
+        int         outOff)
+        throws DataLengthException, IllegalStateException
+    {
+        if (len < 0)
+        {
+            throw new IllegalArgumentException("Can't have a negative input length!");
+        }
+
+        int blockSize   = getBlockSize();
+        int length      = getUpdateOutputSize(len);
+        
+        if (length > 0)
+        {
+            if ((outOff + length) > out.length)
+            {
+                throw new DataLengthException("output buffer too short");
+            }
+        }
+
+        int resultLen = 0;
+        int gapLen = buf.length - bufOff;
+
+        if (len > gapLen)
+        {
+            System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+            resultLen += cipher.processBlock(buf, 0, out, outOff);
+
+            bufOff = 0;
+            len -= gapLen;
+            inOff += gapLen;
+
+            while (len > buf.length)
+            {
+                resultLen += cipher.processBlock(in, inOff, out, outOff + resultLen);
+
+                len -= blockSize;
+                inOff += blockSize;
+            }
+        }
+
+        System.arraycopy(in, inOff, buf, bufOff, len);
+
+        bufOff += len;
+
+        return resultLen;
+    }
+
+    /**
+     * Process the last block in the buffer. If the buffer is currently
+     * full and padding needs to be added a call to doFinal will produce
+     * 2 * getBlockSize() bytes.
+     *
+     * @param out the array the block currently being held is copied into.
+     * @param outOff the offset at which the copying starts.
+     * @return the number of output bytes copied to out.
+     * @exception DataLengthException if there is insufficient space in out for
+     * the output or we are decrypting and the input is not block size aligned.
+     * @exception IllegalStateException if the underlying cipher is not
+     * initialised.
+     * @exception InvalidCipherTextException if padding is expected and not found.
+     */
+    public int doFinal(
+        byte[]  out,
+        int     outOff)
+        throws DataLengthException, IllegalStateException, InvalidCipherTextException
+    {
+        int blockSize = cipher.getBlockSize();
+        int resultLen = 0;
+
+        if (forEncryption)
+        {
+            if (bufOff == blockSize)
+            {
+                if ((outOff + 2 * blockSize) > out.length)
+                {
+                    reset();
+
+                    throw new DataLengthException("output buffer too short");
+                }
+
+                resultLen = cipher.processBlock(buf, 0, out, outOff);
+                bufOff = 0;
+            }
+
+            padding.addPadding(buf, bufOff);
+
+            resultLen += cipher.processBlock(buf, 0, out, outOff + resultLen);
+
+            reset();
+        }
+        else
+        {
+            if (bufOff == blockSize)
+            {
+                resultLen = cipher.processBlock(buf, 0, buf, 0);
+                bufOff = 0;
+            }
+            else
+            {
+                reset();
+
+                throw new DataLengthException("last block incomplete in decryption");
+            }
+
+            try
+            {
+                resultLen -= padding.padCount(buf);
+
+                System.arraycopy(buf, 0, out, outOff, resultLen);
+            }
+            finally
+            {
+                reset();
+            }
+        }
+
+        return resultLen;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/TBCPadding.java b/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/TBCPadding.java
new file mode 100644
index 0000000..219912f
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/TBCPadding.java
@@ -0,0 +1,89 @@
+package org.bouncycastle.crypto.paddings;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * A padder that adds Trailing-Bit-Compliment padding to a block.
+ * <p>
+ * This padding pads the block out with the compliment of the last bit
+ * of the plain text.
+ * </p>
+ */
+public class TBCPadding
+    implements BlockCipherPadding
+{
+    /**
+     * Initialise the padder.
+     *
+     * @param random - a SecureRandom if available.
+     */
+    public void init(SecureRandom random)
+        throws IllegalArgumentException
+    {
+        // nothing to do.
+    }
+
+    /**
+     * Return the name of the algorithm the padder implements.
+     *
+     * @return the name of the algorithm the padder implements.
+     */
+    public String getPaddingName()
+    {
+        return "TBC";
+    }
+
+    /**
+     * add the pad bytes to the passed in block, returning the
+     * number of bytes added.
+     * <p>
+     * Note: this assumes that the last block of plain text is always 
+     * passed to it inside in. i.e. if inOff is zero, indicating the
+     * entire block is to be overwritten with padding the value of in
+     * should be the same as the last block of plain text.
+     * </p>
+     */
+    public int addPadding(
+        byte[]  in,
+        int     inOff)
+    {
+        int     count = in.length - inOff;
+        byte    code;
+        
+        if (inOff > 0)
+        {
+            code = (byte)((in[inOff - 1] & 0x01) == 0 ? 0xff : 0x00);
+        }
+        else
+        {
+            code = (byte)((in[in.length - 1] & 0x01) == 0 ? 0xff : 0x00);
+        }
+            
+        while (inOff < in.length)
+        {
+            in[inOff] = code;
+            inOff++;
+        }
+
+        return count;
+    }
+
+    /**
+     * return the number of pad bytes present in the block.
+     */
+    public int padCount(byte[] in)
+        throws InvalidCipherTextException
+    {
+        byte code = in[in.length - 1];
+
+        int index = in.length - 1;
+        while (index > 0 && in[index - 1] == code)
+        {
+            index--;
+        }
+
+        return in.length - index;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/X923Padding.java b/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/X923Padding.java
new file mode 100644
index 0000000..d4d34aa
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/X923Padding.java
@@ -0,0 +1,80 @@
+package org.bouncycastle.crypto.paddings;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * A padder that adds X9.23 padding to a block - if a SecureRandom is
+ * passed in random padding is assumed, otherwise padding with zeros is used.
+ */
+public class X923Padding
+    implements BlockCipherPadding
+{
+    SecureRandom    random = null;
+
+    /**
+     * Initialise the padder.
+     *
+     * @param random a SecureRandom if one is available.
+     */
+    public void init(SecureRandom random)
+        throws IllegalArgumentException
+    {
+        this.random = random;
+    }
+
+    /**
+     * Return the name of the algorithm the padder implements.
+     *
+     * @return the name of the algorithm the padder implements.
+     */
+    public String getPaddingName()
+    {
+        return "X9.23";
+    }
+
+    /**
+     * add the pad bytes to the passed in block, returning the
+     * number of bytes added.
+     */
+    public int addPadding(
+        byte[]  in,
+        int     inOff)
+    {
+        byte code = (byte)(in.length - inOff);
+
+        while (inOff < in.length - 1)
+        {
+            if (random == null)
+            {
+                in[inOff] = 0;
+            }
+            else
+            {
+                in[inOff] = (byte)random.nextInt();
+            }
+            inOff++;
+        }
+
+        in[inOff] = code;
+
+        return code;
+    }
+
+    /**
+     * return the number of pad bytes present in the block.
+     */
+    public int padCount(byte[] in)
+        throws InvalidCipherTextException
+    {
+        int count = in[in.length - 1] & 0xff;
+
+        if (count > in.length)
+        {
+            throw new InvalidCipherTextException("pad block corrupted");
+        }
+
+        return count;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/ZeroBytePadding.java b/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/ZeroBytePadding.java
new file mode 100644
index 0000000..c756028
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/paddings/ZeroBytePadding.java
@@ -0,0 +1,73 @@
+package org.bouncycastle.crypto.paddings;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * A padder that adds NULL byte padding to a block.
+ */
+public class ZeroBytePadding
+    implements BlockCipherPadding
+{
+    /**
+     * Initialise the padder.
+     *
+     * @param random - a SecureRandom if available.
+     */
+    public void init(SecureRandom random)
+        throws IllegalArgumentException
+    {
+        // nothing to do.
+    }
+
+    /**
+     * Return the name of the algorithm the padder implements.
+     *
+     * @return the name of the algorithm the padder implements.
+     */
+    public String getPaddingName()
+    {
+        return "ZeroByte";
+    }
+
+    /**
+     * add the pad bytes to the passed in block, returning the
+     * number of bytes added.
+     */
+    public int addPadding(
+        byte[]  in,
+        int     inOff)
+    {
+        int added = (in.length - inOff);
+
+        while (inOff < in.length)
+        {
+            in[inOff] = (byte) 0;
+            inOff++;
+        }
+
+        return added;
+    }
+
+    /**
+     * return the number of pad bytes present in the block.
+     */
+    public int padCount(byte[] in)
+        throws InvalidCipherTextException
+    {
+        int count = in.length;
+
+        while (count > 0)
+        {
+            if (in[count - 1] != 0)
+            {
+                break;
+            }
+
+            count--;
+        }
+
+        return in.length - count;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/AsymmetricKeyParameter.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/AsymmetricKeyParameter.java
new file mode 100644
index 0000000..03ba725
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/AsymmetricKeyParameter.java
@@ -0,0 +1,20 @@
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+public class AsymmetricKeyParameter
+    implements CipherParameters
+{
+    boolean privateKey;
+
+    public AsymmetricKeyParameter(
+        boolean privateKey)
+    {
+        this.privateKey = privateKey;
+    }
+
+    public boolean isPrivate()
+    {
+        return privateKey;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/CCMParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/CCMParameters.java
new file mode 100644
index 0000000..17f7344
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/CCMParameters.java
@@ -0,0 +1,48 @@
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+public class CCMParameters
+    implements CipherParameters
+{
+    private byte[] associatedText;
+    private byte[] nonce;
+    private KeyParameter key;
+    private int macSize;
+
+    /**
+     * Base constructor.
+     * 
+     * @param key key to be used by underlying cipher
+     * @param macSize macSize in bits
+     * @param nonce nonce to be used
+     * @param associatedText associated text, if any
+     */
+    public CCMParameters(KeyParameter key, int macSize, byte[] nonce, byte[] associatedText)
+    {
+        this.key = key;
+        this.nonce = nonce;
+        this.macSize = macSize;
+        this.associatedText = associatedText;
+    }
+    
+    public KeyParameter getKey()
+    {
+        return key;
+    }
+    
+    public int getMacSize()
+    {
+        return macSize;
+    }
+    
+    public byte[] getAssociatedText()
+    {
+        return associatedText;
+    }
+    
+    public byte[] getNonce()
+    {
+        return nonce;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/DESParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DESParameters.java
new file mode 100644
index 0000000..5bee360
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DESParameters.java
@@ -0,0 +1,107 @@
+package org.bouncycastle.crypto.params;
+
+public class DESParameters
+    extends KeyParameter
+{
+    public DESParameters(
+        byte[]  key)
+    {
+        super(key);
+
+        if (isWeakKey(key, 0))
+        {
+            throw new IllegalArgumentException("attempt to create weak DES key");
+        }
+    }
+
+    /*
+     * DES Key length in bytes.
+     */
+    static public final int DES_KEY_LENGTH = 8;
+
+    /*
+     * Table of weak and semi-weak keys taken from Schneier pp281
+     */
+    static private final int N_DES_WEAK_KEYS = 16;
+
+    static private byte[] DES_weak_keys =
+    {
+        /* weak keys */
+        (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01,
+        (byte)0x1f,(byte)0x1f,(byte)0x1f,(byte)0x1f, (byte)0x0e,(byte)0x0e,(byte)0x0e,(byte)0x0e,
+        (byte)0xe0,(byte)0xe0,(byte)0xe0,(byte)0xe0, (byte)0xf1,(byte)0xf1,(byte)0xf1,(byte)0xf1,
+        (byte)0xfe,(byte)0xfe,(byte)0xfe,(byte)0xfe, (byte)0xfe,(byte)0xfe,(byte)0xfe,(byte)0xfe,
+
+        /* semi-weak keys */
+        (byte)0x01,(byte)0xfe,(byte)0x01,(byte)0xfe, (byte)0x01,(byte)0xfe,(byte)0x01,(byte)0xfe,
+        (byte)0x1f,(byte)0xe0,(byte)0x1f,(byte)0xe0, (byte)0x0e,(byte)0xf1,(byte)0x0e,(byte)0xf1,
+        (byte)0x01,(byte)0xe0,(byte)0x01,(byte)0xe0, (byte)0x01,(byte)0xf1,(byte)0x01,(byte)0xf1,
+        (byte)0x1f,(byte)0xfe,(byte)0x1f,(byte)0xfe, (byte)0x0e,(byte)0xfe,(byte)0x0e,(byte)0xfe,
+        (byte)0x01,(byte)0x1f,(byte)0x01,(byte)0x1f, (byte)0x01,(byte)0x0e,(byte)0x01,(byte)0x0e,
+        (byte)0xe0,(byte)0xfe,(byte)0xe0,(byte)0xfe, (byte)0xf1,(byte)0xfe,(byte)0xf1,(byte)0xfe,
+        (byte)0xfe,(byte)0x01,(byte)0xfe,(byte)0x01, (byte)0xfe,(byte)0x01,(byte)0xfe,(byte)0x01,
+        (byte)0xe0,(byte)0x1f,(byte)0xe0,(byte)0x1f, (byte)0xf1,(byte)0x0e,(byte)0xf1,(byte)0x0e,
+        (byte)0xe0,(byte)0x01,(byte)0xe0,(byte)0x01, (byte)0xf1,(byte)0x01,(byte)0xf1,(byte)0x01,
+        (byte)0xfe,(byte)0x1f,(byte)0xfe,(byte)0x1f, (byte)0xfe,(byte)0x0e,(byte)0xfe,(byte)0x0e,
+        (byte)0x1f,(byte)0x01,(byte)0x1f,(byte)0x01, (byte)0x0e,(byte)0x01,(byte)0x0e,(byte)0x01,
+        (byte)0xfe,(byte)0xe0,(byte)0xfe,(byte)0xe0, (byte)0xfe,(byte)0xf1,(byte)0xfe,(byte)0xf1
+    };
+
+    /**
+     * DES has 16 weak keys.  This method will check
+     * if the given DES key material is weak or semi-weak.
+     * Key material that is too short is regarded as weak.
+     * <p>
+     * See <a href="http://www.counterpane.com/applied.html">"Applied
+     * Cryptography"</a> by Bruce Schneier for more information.
+     *
+     * @return true if the given DES key material is weak or semi-weak,
+     *     false otherwise.
+     */
+    public static boolean isWeakKey(
+        byte[] key,
+        int offset)
+    {
+        if (key.length - offset < DES_KEY_LENGTH)
+        {
+            throw new IllegalArgumentException("key material too short.");
+        }
+
+        nextkey: for (int i = 0; i < N_DES_WEAK_KEYS; i++)
+        {
+            for (int j = 0; j < DES_KEY_LENGTH; j++)
+            {
+                if (key[j + offset] != DES_weak_keys[i * DES_KEY_LENGTH + j])
+                {
+                    continue nextkey;
+                }
+            }
+
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * DES Keys use the LSB as the odd parity bit.  This can
+     * be used to check for corrupt keys.
+     *
+     * @param bytes the byte array to set the parity on.
+     */
+    public static void setOddParity(
+        byte[] bytes)
+    {
+        for (int i = 0; i < bytes.length; i++)
+        {
+            int b = bytes[i];
+            bytes[i] = (byte)((b & 0xfe) |
+                            ((((b >> 1) ^
+                            (b >> 2) ^
+                            (b >> 3) ^
+                            (b >> 4) ^
+                            (b >> 5) ^
+                            (b >> 6) ^
+                            (b >> 7)) ^ 0x01) & 0x01));
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/DESedeParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DESedeParameters.java
new file mode 100644
index 0000000..d424fc1
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DESedeParameters.java
@@ -0,0 +1,57 @@
+package org.bouncycastle.crypto.params;
+
+public class DESedeParameters
+    extends DESParameters
+{
+    /*
+     * DES-EDE Key length in bytes.
+     */
+    static public final int DES_EDE_KEY_LENGTH = 24;
+
+    public DESedeParameters(
+        byte[]  key)
+    {
+        super(key);
+
+        if (isWeakKey(key, 0, 0))
+        {
+            throw new IllegalArgumentException("attempt to create weak DESede key");
+        }
+    }
+
+    /**
+     * return true if the passed in key is a DES-EDE weak key.
+     *
+     * @param key bytes making up the key
+     * @param offset offset into the byte array the key starts at
+     * @param length number of bytes making up the key
+     */
+    public static boolean isWeakKey(
+        byte[]  key,
+        int     offset,
+        int     length)
+    {
+        for (int i = offset; i < length; i += DES_KEY_LENGTH)
+        {
+            if (DESParameters.isWeakKey(key, i))
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * return true if the passed in key is a DES-EDE weak key.
+     *
+     * @param key bytes making up the key
+     * @param offset offset into the byte array the key starts at
+     */
+    public static boolean isWeakKey(
+        byte[]  key,
+        int     offset)
+    {
+        return isWeakKey(key, offset, key.length - offset);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/DHKeyGenerationParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DHKeyGenerationParameters.java
new file mode 100644
index 0000000..910081e
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DHKeyGenerationParameters.java
@@ -0,0 +1,25 @@
+package org.bouncycastle.crypto.params;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.KeyGenerationParameters;
+
+public class DHKeyGenerationParameters
+    extends KeyGenerationParameters
+{
+    private DHParameters    params;
+
+    public DHKeyGenerationParameters(
+        SecureRandom    random,
+        DHParameters    params)
+    {
+        super(random, params.getP().bitLength());
+
+        this.params = params;
+    }
+
+    public DHParameters getParameters()
+    {
+        return params;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/DHKeyParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DHKeyParameters.java
new file mode 100644
index 0000000..e686f35
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DHKeyParameters.java
@@ -0,0 +1,54 @@
+package org.bouncycastle.crypto.params;
+
+
+public class DHKeyParameters
+    extends AsymmetricKeyParameter
+{
+    private DHParameters    params;
+
+    protected DHKeyParameters(
+        boolean         isPrivate,
+        DHParameters    params)
+    {
+        super(isPrivate);
+
+        this.params = params;
+    }   
+
+    public DHParameters getParameters()
+    {
+        return params;
+    }
+
+    public boolean equals(
+        Object  obj)
+    {
+        if (!(obj instanceof DHKeyParameters))
+        {
+            return false;
+        }
+
+        DHKeyParameters    dhKey = (DHKeyParameters)obj;
+
+        if (params == null)
+        {
+            return dhKey.getParameters() == null;
+        }
+        else
+        { 
+            return params.equals(dhKey.getParameters());
+        }
+    }
+    
+    public int hashCode()
+    {
+        int code = isPrivate() ? 0 : 1;
+        
+        if (params != null)
+        {
+            code ^= params.hashCode();
+        }
+        
+        return code;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/DHParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DHParameters.java
new file mode 100644
index 0000000..def449c
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DHParameters.java
@@ -0,0 +1,126 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+public class DHParameters
+    implements CipherParameters
+{
+    private BigInteger              g;
+    private BigInteger              p;
+    private BigInteger              q;
+    private int                     j;
+    private DHValidationParameters  validation;
+
+    public DHParameters(
+        BigInteger  p,
+        BigInteger  g)
+    {
+        this.g = g;
+        this.p = p;
+    }
+
+    public DHParameters(
+        BigInteger  p,
+        BigInteger  g,
+        BigInteger  q,
+        int         j)
+    {
+        this.g = g;
+        this.p = p;
+        this.q = q;
+        this.j = j;
+    }   
+
+    public DHParameters(
+        BigInteger              p,
+        BigInteger              g,
+        BigInteger              q,
+        int                     j,
+        DHValidationParameters  validation)
+    {
+        this.g = g;
+        this.p = p;
+        this.q = q;
+        this.j = j;
+    }   
+
+    public BigInteger getP()
+    {
+        return p;
+    }
+
+    public BigInteger getG()
+    {
+        return g;
+    }
+
+    public BigInteger getQ()
+    {
+        return q;
+    }
+
+    /**
+     * Return the private value length in bits - if set, zero otherwise (use bitLength(P) - 1).
+     * 
+     * @return the private value length in bits, zero otherwise.
+     */
+    public int getJ()
+    {
+        return j;
+    }
+
+    public DHValidationParameters getValidationParameters()
+    {
+        return validation;
+    }
+
+    public boolean equals(
+        Object  obj)
+    {
+        if (!(obj instanceof DHParameters))
+        {
+            return false;
+        }
+
+        DHParameters    pm = (DHParameters)obj;
+
+        if (this.getValidationParameters() != null)
+        {
+            if (!this.getValidationParameters().equals(pm.getValidationParameters()))
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if (pm.getValidationParameters() != null)
+            {
+                return false;
+            }
+        }
+
+        if (this.getQ() != null)
+        {
+            if (!this.getQ().equals(pm.getQ()))
+            {
+                return false;
+            }
+        }
+        else
+        {
+            if (pm.getQ() != null)
+            {
+                return false;
+            }
+        }
+        
+        return (j == pm.getJ()) && pm.getP().equals(p) && pm.getG().equals(g);
+    }
+    
+    public int hashCode()
+    {
+        return getJ() ^ getP().hashCode() ^ getG().hashCode();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/DHPrivateKeyParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DHPrivateKeyParameters.java
new file mode 100644
index 0000000..523f9a0
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DHPrivateKeyParameters.java
@@ -0,0 +1,41 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+public class DHPrivateKeyParameters
+    extends DHKeyParameters
+{
+    private BigInteger      x;
+
+    public DHPrivateKeyParameters(
+        BigInteger      x,
+        DHParameters    params)
+    {
+        super(true, params);
+
+        this.x = x;
+    }   
+
+    public BigInteger getX()
+    {
+        return x;
+    }
+
+    public boolean equals(
+        Object  obj)
+    {
+        if (!(obj instanceof DHPrivateKeyParameters))
+        {
+            return false;
+        }
+
+        DHPrivateKeyParameters  pKey = (DHPrivateKeyParameters)obj;
+
+        if (!pKey.getX().equals(x))
+        {
+            return false;
+        }
+
+        return super.equals(obj);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/DHPublicKeyParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DHPublicKeyParameters.java
new file mode 100644
index 0000000..4f308ed
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DHPublicKeyParameters.java
@@ -0,0 +1,41 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+public class DHPublicKeyParameters
+    extends DHKeyParameters
+{
+    private BigInteger      y;
+
+    public DHPublicKeyParameters(
+        BigInteger      y,
+        DHParameters    params)
+    {
+        super(false, params);
+
+        this.y = y;
+    }   
+
+    public BigInteger getY()
+    {
+        return y;
+    }
+
+    public boolean equals(
+        Object  obj)
+    {
+        if (!(obj instanceof DHPublicKeyParameters))
+        {
+            return false;
+        }
+
+        DHPublicKeyParameters   pKey = (DHPublicKeyParameters)obj;
+
+        if (!pKey.getY().equals(y))
+        {
+            return false;
+        }
+
+        return super.equals(obj);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/DHValidationParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DHValidationParameters.java
new file mode 100644
index 0000000..94c1360
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DHValidationParameters.java
@@ -0,0 +1,58 @@
+package org.bouncycastle.crypto.params;
+
+public class DHValidationParameters
+{
+    private byte[]  seed;
+    private int     counter;
+
+    public DHValidationParameters(
+        byte[]  seed,
+        int     counter)
+    {
+        this.seed = seed;
+        this.counter = counter;
+    }
+
+    public boolean equals(
+        Object o)
+    {
+        if (!(o instanceof DHValidationParameters))
+        {
+            return false;
+        }
+
+        DHValidationParameters  other = (DHValidationParameters)o;
+
+        if (other.counter != this.counter)
+        {
+            return false;
+        }
+
+        if (other.seed.length != this.seed.length)
+        {
+            return false;
+        }
+
+        for (int i = 0; i != other.seed.length; i++)
+        {
+            if (other.seed[i] != this.seed[i])
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+    
+    public int hashCode()
+    {
+        int code = counter;
+        
+        for (int i = 0; i != seed.length; i++)
+        {
+            code ^= (seed[i] & 0xff) << (i % 4);
+        }
+        
+        return code;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/DSAKeyGenerationParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DSAKeyGenerationParameters.java
new file mode 100644
index 0000000..29fa91e
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DSAKeyGenerationParameters.java
@@ -0,0 +1,25 @@
+package org.bouncycastle.crypto.params;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.KeyGenerationParameters;
+
+public class DSAKeyGenerationParameters
+    extends KeyGenerationParameters
+{
+    private DSAParameters    params;
+
+    public DSAKeyGenerationParameters(
+        SecureRandom    random,
+        DSAParameters   params)
+    {
+        super(random, params.getP().bitLength() - 1);
+
+        this.params = params;
+    }
+
+    public DSAParameters getParameters()
+    {
+        return params;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/DSAKeyParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DSAKeyParameters.java
new file mode 100644
index 0000000..11bb9d9
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DSAKeyParameters.java
@@ -0,0 +1,21 @@
+package org.bouncycastle.crypto.params;
+
+public class DSAKeyParameters
+    extends AsymmetricKeyParameter
+{
+    private DSAParameters    params;
+
+    public DSAKeyParameters(
+        boolean         isPrivate,
+        DSAParameters   params)
+    {
+        super(isPrivate);
+
+        this.params = params;
+    }   
+
+    public DSAParameters getParameters()
+    {
+        return params;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/DSAParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DSAParameters.java
new file mode 100644
index 0000000..7f76d11
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DSAParameters.java
@@ -0,0 +1,74 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+public class DSAParameters
+    implements CipherParameters
+{
+    private BigInteger              g;
+    private BigInteger              q;
+    private BigInteger              p;
+    private DSAValidationParameters validation;
+
+    public DSAParameters(
+        BigInteger  p,
+        BigInteger  q,
+        BigInteger  g)
+    {
+        this.g = g;
+        this.p = p;
+        this.q = q;
+    }   
+
+    public DSAParameters(
+        BigInteger              p,
+        BigInteger              q,
+        BigInteger              g,
+        DSAValidationParameters params)
+    {
+        this.g = g;
+        this.p = p;
+        this.q = q;
+        this.validation = params;
+    }   
+
+    public BigInteger getP()
+    {
+        return p;
+    }
+
+    public BigInteger getQ()
+    {
+        return q;
+    }
+
+    public BigInteger getG()
+    {
+        return g;
+    }
+
+    public DSAValidationParameters getValidationParameters()
+    {
+        return validation;
+    }
+
+    public boolean equals(
+        Object  obj)
+    {
+        if (!(obj instanceof DSAParameters))
+        {
+            return false;
+        }
+
+        DSAParameters    pm = (DSAParameters)obj;
+
+        return (pm.getP().equals(p) && pm.getQ().equals(q) && pm.getG().equals(g));
+    }
+    
+    public int hashCode()
+    {
+        return getP().hashCode() ^ getQ().hashCode() ^ getG().hashCode();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/DSAPrivateKeyParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DSAPrivateKeyParameters.java
new file mode 100644
index 0000000..3bef3f4
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DSAPrivateKeyParameters.java
@@ -0,0 +1,23 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+public class DSAPrivateKeyParameters
+    extends DSAKeyParameters
+{
+    private BigInteger      x;
+
+    public DSAPrivateKeyParameters(
+        BigInteger      x,
+        DSAParameters   params)
+    {
+        super(true, params);
+
+        this.x = x;
+    }   
+
+    public BigInteger getX()
+    {
+        return x;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/DSAPublicKeyParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DSAPublicKeyParameters.java
new file mode 100644
index 0000000..c006656
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DSAPublicKeyParameters.java
@@ -0,0 +1,23 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+public class DSAPublicKeyParameters
+    extends DSAKeyParameters
+{
+    private BigInteger      y;
+
+    public DSAPublicKeyParameters(
+        BigInteger      y,
+        DSAParameters   params)
+    {
+        super(false, params);
+
+        this.y = y;
+    }   
+
+    public BigInteger getY()
+    {
+        return y;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/DSAValidationParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DSAValidationParameters.java
new file mode 100644
index 0000000..541218b
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/DSAValidationParameters.java
@@ -0,0 +1,56 @@
+package org.bouncycastle.crypto.params;
+
+public class DSAValidationParameters
+{
+    private byte[]  seed;
+    private int     counter;
+
+    public DSAValidationParameters(
+        byte[]  seed,
+        int     counter)
+    {
+        this.seed = seed;
+        this.counter = counter;
+    }
+
+    public int getCounter()
+    {
+        return counter;
+    }
+
+    public byte[] getSeed()
+    {
+        return seed;
+    }
+
+    public boolean equals(
+        Object o)
+    {
+        if (!(o instanceof DSAValidationParameters))
+        {
+            return false;
+        }
+
+        DSAValidationParameters  other = (DSAValidationParameters)o;
+
+        if (other.counter != this.counter)
+        {
+            return false;
+        }
+
+        if (other.seed.length != this.seed.length)
+        {
+            return false;
+        }
+
+        for (int i = 0; i != other.seed.length; i++)
+        {
+            if (other.seed[i] != this.seed[i])
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/IESParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/IESParameters.java
new file mode 100644
index 0000000..0600b34
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/IESParameters.java
@@ -0,0 +1,44 @@
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+/**
+ * parameters for using an integrated cipher in stream mode.
+ */
+public class IESParameters
+    implements CipherParameters
+{
+    private byte[]  derivation;
+    private byte[]  encoding;
+    private int     macKeySize;
+
+    /**
+     * @param derivation the derivation parameter for the KDF function.
+     * @param encoding the encoding parameter for the KDF function.
+     * @param macKeySize the size of the MAC key (in bits).
+     */
+    public IESParameters(
+        byte[]  derivation,
+        byte[]  encoding,
+        int     macKeySize)
+    {
+        this.derivation = derivation;
+        this.encoding = encoding;
+        this.macKeySize = macKeySize;
+    }
+
+    public byte[] getDerivationV()
+    {
+        return derivation;
+    }
+
+    public byte[] getEncodingV()
+    {
+        return encoding;
+    }
+
+    public int getMacKeySize()
+    {
+        return macKeySize;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/IESWithCipherParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/IESWithCipherParameters.java
new file mode 100644
index 0000000..ef61b2c
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/IESWithCipherParameters.java
@@ -0,0 +1,30 @@
+package org.bouncycastle.crypto.params;
+
+
+public class IESWithCipherParameters
+    extends IESParameters
+{
+    private int cipherKeySize;
+
+    /**
+     * @param derivation the derivation parameter for the KDF function.
+     * @param encoding the encoding parameter for the KDF function.
+     * @param macKeySize the size of the MAC key (in bits).
+     * @param cipherKeySize the size of the associated Cipher key (in bits).
+     */
+    public IESWithCipherParameters(
+        byte[]  derivation,
+        byte[]  encoding,
+        int     macKeySize,
+        int     cipherKeySize)
+    {
+        super(derivation, encoding, macKeySize);
+
+        this.cipherKeySize = cipherKeySize;
+    }
+
+    public int getCipherKeySize()
+    {
+        return cipherKeySize;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/ISO18033KDFParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/ISO18033KDFParameters.java
new file mode 100644
index 0000000..8dffe2e
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/ISO18033KDFParameters.java
@@ -0,0 +1,23 @@
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.crypto.DerivationParameters;
+
+/**
+ * parameters for Key derivation functions for ISO-18033
+ */
+public class ISO18033KDFParameters
+    implements DerivationParameters
+{
+    byte[]  seed;
+
+    public ISO18033KDFParameters(
+        byte[]  seed)
+    {
+        this.seed = seed;
+    }
+
+    public byte[] getSeed()
+    {
+        return seed;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/KDFParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/KDFParameters.java
new file mode 100644
index 0000000..f3bac64
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/KDFParameters.java
@@ -0,0 +1,31 @@
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.crypto.DerivationParameters;
+
+/**
+ * parameters for Key derivation functions for IEEE P1363a
+ */
+public class KDFParameters
+    implements DerivationParameters
+{
+    byte[]  iv;
+    byte[]  shared;
+
+    public KDFParameters(
+        byte[]  shared,
+        byte[]  iv)
+    {
+        this.shared = shared;
+        this.iv = iv;
+    }
+
+    public byte[] getSharedSecret()
+    {
+        return shared;
+    }
+
+    public byte[] getIV()
+    {
+        return iv;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/KeyParameter.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/KeyParameter.java
new file mode 100644
index 0000000..5c4fe0e
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/KeyParameter.java
@@ -0,0 +1,30 @@
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+public class KeyParameter
+    implements CipherParameters
+{
+    private byte[]  key;
+
+    public KeyParameter(
+        byte[]  key)
+    {
+        this(key, 0, key.length);
+    }
+
+    public KeyParameter(
+        byte[]  key,
+        int     keyOff,
+        int     keyLen)
+    {
+        this.key = new byte[keyLen];
+
+        System.arraycopy(key, keyOff, this.key, 0, keyLen);
+    }
+
+    public byte[] getKey()
+    {
+        return key;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/MGFParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/MGFParameters.java
new file mode 100644
index 0000000..8c1ea5e
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/MGFParameters.java
@@ -0,0 +1,32 @@
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.crypto.DerivationParameters;
+
+/**
+ * parameters for mask derivation functions.
+ */
+public class MGFParameters
+    implements DerivationParameters
+{
+    byte[]  seed;
+
+    public MGFParameters(
+        byte[]  seed)
+    {
+        this.seed = seed;
+    }
+
+    public MGFParameters(
+        byte[]  seed,
+        int     off,
+        int     len)
+    {
+        this.seed = new byte[len];
+        System.arraycopy(seed, off, this.seed, 0, len);
+    }
+
+    public byte[] getSeed()
+    {
+        return seed;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/ParametersWithIV.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/ParametersWithIV.java
new file mode 100644
index 0000000..4a1e6e9
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/ParametersWithIV.java
@@ -0,0 +1,39 @@
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+public class ParametersWithIV
+    implements CipherParameters
+{
+    private byte[]              iv;
+    private CipherParameters    parameters;
+
+    public ParametersWithIV(
+        CipherParameters    parameters,
+        byte[]              iv)
+    {
+        this(parameters, iv, 0, iv.length);
+    }
+
+    public ParametersWithIV(
+        CipherParameters    parameters,
+        byte[]              iv,
+        int                 ivOff,
+        int                 ivLen)
+    {
+        this.iv = new byte[ivLen];
+        this.parameters = parameters;
+
+        System.arraycopy(iv, ivOff, this.iv, 0, ivLen);
+    }
+
+    public byte[] getIV()
+    {
+        return iv;
+    }
+
+    public CipherParameters getParameters()
+    {
+        return parameters;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/ParametersWithRandom.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/ParametersWithRandom.java
new file mode 100644
index 0000000..f8b7c82
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/ParametersWithRandom.java
@@ -0,0 +1,41 @@
+package org.bouncycastle.crypto.params;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+public class ParametersWithRandom
+    implements CipherParameters
+{
+    private SecureRandom        random;
+    private CipherParameters    parameters;
+
+    public ParametersWithRandom(
+        CipherParameters    parameters,
+        SecureRandom        random)
+    {
+        this.random = random;
+        this.parameters = parameters;
+    }
+
+    public ParametersWithRandom(
+        CipherParameters    parameters)
+    {
+        this.random = null;
+        this.parameters = parameters;
+    }
+
+    public SecureRandom getRandom()
+    {
+        if (random == null)
+        {
+            random = new SecureRandom();
+        }
+        return random;
+    }
+
+    public CipherParameters getParameters()
+    {
+        return parameters;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/ParametersWithSBox.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/ParametersWithSBox.java
new file mode 100644
index 0000000..b226a9d
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/ParametersWithSBox.java
@@ -0,0 +1,28 @@
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+public class ParametersWithSBox
+    implements CipherParameters
+{
+    private CipherParameters  parameters;
+    private byte[]            sBox;
+
+    public ParametersWithSBox(
+        CipherParameters parameters,
+        byte[]           sBox)
+    {
+        this.parameters = parameters;
+        this.sBox = sBox;
+    }
+
+    public byte[] getSBox()
+    {
+        return sBox;
+    }
+
+    public CipherParameters getParameters()
+    {
+        return parameters;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/ParametersWithSalt.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/ParametersWithSalt.java
new file mode 100644
index 0000000..73765dd
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/ParametersWithSalt.java
@@ -0,0 +1,42 @@
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+/**
+ * Cipher parameters with a fixed salt value associated with them.
+ */
+public class ParametersWithSalt
+    implements CipherParameters
+{
+    private byte[]              salt;
+    private CipherParameters    parameters;
+
+    public ParametersWithSalt(
+        CipherParameters    parameters,
+        byte[]              salt)
+    {
+        this(parameters, salt, 0, salt.length);
+    }
+
+    public ParametersWithSalt(
+        CipherParameters    parameters,
+        byte[]              salt,
+        int                 saltOff,
+        int                 saltLen)
+    {
+        this.salt = new byte[saltLen];
+        this.parameters = parameters;
+
+        System.arraycopy(salt, saltOff, this.salt, 0, saltLen);
+    }
+
+    public byte[] getSalt()
+    {
+        return salt;
+    }
+
+    public CipherParameters getParameters()
+    {
+        return parameters;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/RC2Parameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/RC2Parameters.java
new file mode 100644
index 0000000..dc33ec5
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/RC2Parameters.java
@@ -0,0 +1,36 @@
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+public class RC2Parameters
+    implements CipherParameters
+{
+    private byte[]  key;
+    private int     bits;
+
+    public RC2Parameters(
+        byte[]  key)
+    {
+        this(key, (key.length > 128) ? 1024 : (key.length * 8));
+    }
+
+    public RC2Parameters(
+        byte[]  key,
+        int     bits)
+    {
+        this.key = new byte[key.length];
+        this.bits = bits;
+
+        System.arraycopy(key, 0, this.key, 0, key.length);
+    }
+
+    public byte[] getKey()
+    {
+        return key;
+    }
+
+    public int getEffectiveKeyBits()
+    {
+        return bits;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/RC5Parameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/RC5Parameters.java
new file mode 100644
index 0000000..6cbd57f
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/RC5Parameters.java
@@ -0,0 +1,35 @@
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+public class RC5Parameters
+    implements CipherParameters
+{
+    private byte[]  key;
+    private int     rounds;
+
+    public RC5Parameters(
+        byte[]  key,
+        int     rounds)
+    {
+        if (key.length > 255)
+        {
+            throw new IllegalArgumentException("RC5 key length can be no greater than 255");
+        }
+
+        this.key = new byte[key.length];
+        this.rounds = rounds;
+
+        System.arraycopy(key, 0, this.key, 0, key.length);
+    }
+
+    public byte[] getKey()
+    {
+        return key;
+    }
+
+    public int getRounds()
+    {
+        return rounds;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/RSAKeyGenerationParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/RSAKeyGenerationParameters.java
new file mode 100644
index 0000000..38b55fc
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/RSAKeyGenerationParameters.java
@@ -0,0 +1,48 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.KeyGenerationParameters;
+
+public class RSAKeyGenerationParameters
+    extends KeyGenerationParameters
+{
+    private BigInteger publicExponent;
+    private int certainty;
+
+    public RSAKeyGenerationParameters(
+        BigInteger      publicExponent,
+        SecureRandom    random,
+        int             strength,
+        int             certainty)
+    {
+        super(random, strength);
+
+        if (strength < 12)
+        {
+            throw new IllegalArgumentException("key strength too small");
+        }
+
+        //
+        // public exponent cannot be even
+        //
+        if (!publicExponent.testBit(0)) 
+        {
+                throw new IllegalArgumentException("public exponent cannot be even");
+        }
+        
+        this.publicExponent = publicExponent;
+        this.certainty = certainty;
+    }
+
+    public BigInteger getPublicExponent()
+    {
+        return publicExponent;
+    }
+
+    public int getCertainty()
+    {
+        return certainty;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/RSAKeyParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/RSAKeyParameters.java
new file mode 100644
index 0000000..4a2d935
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/RSAKeyParameters.java
@@ -0,0 +1,31 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+public class RSAKeyParameters
+    extends AsymmetricKeyParameter
+{
+    private BigInteger      modulus;
+    private BigInteger      exponent;
+
+    public RSAKeyParameters(
+        boolean     isPrivate,
+        BigInteger  modulus,
+        BigInteger  exponent)
+    {
+        super(isPrivate);
+
+        this.modulus = modulus;
+        this.exponent = exponent;
+    }   
+
+    public BigInteger getModulus()
+    {
+        return modulus;
+    }
+
+    public BigInteger getExponent()
+    {
+        return exponent;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/params/RSAPrivateCrtKeyParameters.java b/libcore/security/src/main/java/org/bouncycastle/crypto/params/RSAPrivateCrtKeyParameters.java
new file mode 100644
index 0000000..b61cb5c
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/params/RSAPrivateCrtKeyParameters.java
@@ -0,0 +1,67 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+public class RSAPrivateCrtKeyParameters
+    extends RSAKeyParameters
+{
+    private BigInteger  e;
+    private BigInteger  p;
+    private BigInteger  q;
+    private BigInteger  dP;
+    private BigInteger  dQ;
+    private BigInteger  qInv;
+
+    /**
+     * 
+     */
+    public RSAPrivateCrtKeyParameters(
+        BigInteger  modulus,
+        BigInteger  publicExponent,
+        BigInteger  privateExponent,
+        BigInteger  p,
+        BigInteger  q,
+        BigInteger  dP,
+        BigInteger  dQ,
+        BigInteger  qInv)
+    {
+        super(true, modulus, privateExponent);
+
+        this.e = publicExponent;
+        this.p = p;
+        this.q = q;
+        this.dP = dP;
+        this.dQ = dQ;
+        this.qInv = qInv;
+    }
+
+    public BigInteger getPublicExponent()
+    {
+        return e;
+    }
+
+    public BigInteger getP()
+    {
+        return p;
+    }
+
+    public BigInteger getQ()
+    {
+        return q;
+    }
+
+    public BigInteger getDP()
+    {
+        return dP;
+    }
+
+    public BigInteger getDQ()
+    {
+        return dQ;
+    }
+
+    public BigInteger getQInv()
+    {
+        return qInv;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java b/libcore/security/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java
new file mode 100644
index 0000000..a8392ab
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java
@@ -0,0 +1,122 @@
+package org.bouncycastle.crypto.signers;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DSA;
+import org.bouncycastle.crypto.params.DSAKeyParameters;
+import org.bouncycastle.crypto.params.DSAParameters;
+import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+
+/**
+ * The Digital Signature Algorithm - as described in "Handbook of Applied
+ * Cryptography", pages 452 - 453.
+ */
+public class DSASigner
+    implements DSA
+{
+    DSAKeyParameters key;
+
+    SecureRandom    random;
+
+    public void init(
+        boolean                 forSigning,
+        CipherParameters        param)
+    {
+        if (forSigning)
+        {
+            if (param instanceof ParametersWithRandom)
+            {
+                ParametersWithRandom    rParam = (ParametersWithRandom)param;
+
+                this.random = rParam.getRandom();
+                this.key = (DSAPrivateKeyParameters)rParam.getParameters();
+            }
+            else
+            {
+                this.random = new SecureRandom();
+                this.key = (DSAPrivateKeyParameters)param;
+            }
+        }
+        else
+        {
+            this.key = (DSAPublicKeyParameters)param;
+        }
+    }
+
+    /**
+     * generate a signature for the given message using the key we were
+     * initialised with. For conventional DSA the message should be a SHA-1
+     * hash of the message of interest.
+     *
+     * @param message the message that will be verified later.
+     */
+    public BigInteger[] generateSignature(
+        byte[] message)
+    {
+        BigInteger      m = new BigInteger(1, message);
+        DSAParameters   params = key.getParameters();
+        BigInteger      k;
+        int                  qBitLength = params.getQ().bitLength();
+
+        do 
+        {
+            k = new BigInteger(qBitLength, random);
+        }
+        while (k.compareTo(params.getQ()) >= 0);
+
+        BigInteger  r = params.getG().modPow(k, params.getP()).mod(params.getQ());
+
+        k = k.modInverse(params.getQ()).multiply(
+                    m.add(((DSAPrivateKeyParameters)key).getX().multiply(r)));
+
+        BigInteger  s = k.mod(params.getQ());
+
+        BigInteger[]  res = new BigInteger[2];
+
+        res[0] = r;
+        res[1] = s;
+
+        return res;
+    }
+
+    /**
+     * return true if the value r and s represent a DSA signature for
+     * the passed in message for standard DSA the message should be a
+     * SHA-1 hash of the real message to be verified.
+     */
+    public boolean verifySignature(
+        byte[]      message,
+        BigInteger  r,
+        BigInteger  s)
+    {
+        BigInteger      m = new BigInteger(1, message);
+        DSAParameters   params = key.getParameters();
+        BigInteger      zero = BigInteger.valueOf(0);
+
+        if (zero.compareTo(r) >= 0 || params.getQ().compareTo(r) <= 0)
+        {
+            return false;
+        }
+
+        if (zero.compareTo(s) >= 0 || params.getQ().compareTo(s) <= 0)
+        {
+            return false;
+        }
+
+        BigInteger  w = s.modInverse(params.getQ());
+
+        BigInteger  u1 = m.multiply(w).mod(params.getQ());
+        BigInteger  u2 = r.multiply(w).mod(params.getQ());
+
+        u1 = params.getG().modPow(u1, params.getP());
+        u2 = ((DSAPublicKeyParameters)key).getY().modPow(u2, params.getP());
+
+        BigInteger  v = u1.multiply(u2).mod(params.getP()).mod(params.getQ());
+
+        return v.equals(r);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/signers/ISO9796d2PSSSigner.java b/libcore/security/src/main/java/org/bouncycastle/crypto/signers/ISO9796d2PSSSigner.java
new file mode 100644
index 0000000..b617758
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/signers/ISO9796d2PSSSigner.java
@@ -0,0 +1,611 @@
+package org.bouncycastle.crypto.signers;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.CryptoException;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.SignerWithRecovery;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.RIPEMD128Digest;
+// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
+// END android-removed
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.crypto.params.ParametersWithSalt;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+
+/**
+ * ISO9796-2 - mechanism using a hash function with recovery (scheme 2 and 3).
+ * <p>
+ * Note: the usual length for the salt is the length of the hash 
+ * function used in bytes.
+ */
+public class ISO9796d2PSSSigner
+    implements SignerWithRecovery
+{
+    static final public int   TRAILER_IMPLICIT    = 0xBC;
+    static final public int   TRAILER_RIPEMD160   = 0x31CC;
+    static final public int   TRAILER_RIPEMD128   = 0x32CC;
+    static final public int   TRAILER_SHA1        = 0x33CC;
+
+    private Digest                      digest;
+    private AsymmetricBlockCipher       cipher;
+    
+    private SecureRandom                random;
+    private byte[]                      standardSalt;
+
+    private int         hLen;
+    private int         trailer;
+    private int         keyBits;
+    private byte[]      block;
+    private byte[]      mBuf;
+    private int         messageLength;
+    private int         saltLength;
+    private boolean     fullMessage;
+    private byte[]      recoveredMessage;
+
+    /**
+     * Generate a signer for the with either implicit or explicit trailers
+     * for ISO9796-2, scheme 2 or 3.
+     * 
+     * @param cipher base cipher to use for signature creation/verification
+     * @param digest digest to use.
+     * @param saltLength length of salt in bytes.
+     * @param implicit whether or not the trailer is implicit or gives the hash.
+     */
+    public ISO9796d2PSSSigner(
+        AsymmetricBlockCipher   cipher,
+        Digest                  digest,
+        int                     saltLength,
+        boolean                 implicit)
+    {
+        this.cipher = cipher;
+        this.digest = digest;
+        this.hLen = digest.getDigestSize();
+        this.saltLength = saltLength;
+
+        if (implicit)
+        {
+            trailer = TRAILER_IMPLICIT;
+        }
+        else
+        {
+            if (digest instanceof SHA1Digest)
+            {
+                trailer = TRAILER_SHA1;
+            }
+            // BEGIN android-removed
+            // else if (digest instanceof RIPEMD160Digest)
+            // {
+            //     trailer = TRAILER_RIPEMD160;
+            // }
+            // else if (digest instanceof RIPEMD128Digest)
+            // {
+            //     trailer = TRAILER_RIPEMD128;
+            // }
+            // END android-removed
+            else
+            {
+                throw new IllegalArgumentException("no valid trailer for digest");
+            }
+        }
+    }
+
+    /**
+     * Constructor for a signer with an explicit digest trailer.
+     * 
+     * @param cipher cipher to use.
+     * @param digest digest to sign with.
+     * @param saltLength length of salt in bytes.
+     */
+    public ISO9796d2PSSSigner(
+        AsymmetricBlockCipher   cipher,
+        Digest                  digest,
+        int                     saltLength)
+    {
+        this(cipher, digest, saltLength, false);
+    }
+    
+    /**
+     * Initialise the signer.
+     * 
+     * @param forSigning true if for signing, false if for verification.
+     * @param param parameters for signature generation/verification. If the
+     * parameters are for generation they should be a ParametersWithRandom,
+     * a ParametersWithSalt, or just an RSAKeyParameters object. If RSAKeyParameters
+     * are passed in a SecureRandom will be created.
+     * @exception IllegalArgumentException if wrong parameter type or a fixed 
+     * salt is passed in which is the wrong length.
+     */
+    public void init(
+        boolean                 forSigning,
+        CipherParameters        param)
+    {
+        RSAKeyParameters    kParam = null;
+        int                    lengthOfSalt = saltLength;
+
+        if (param instanceof ParametersWithRandom)
+        {
+            ParametersWithRandom    p = (ParametersWithRandom)param;
+
+            kParam = (RSAKeyParameters)p.getParameters();
+            random = p.getRandom();
+        }
+        else if (param instanceof ParametersWithSalt)
+        {
+            ParametersWithSalt    p = (ParametersWithSalt)param;
+
+            kParam = (RSAKeyParameters)p.getParameters();
+            standardSalt = p.getSalt();
+            lengthOfSalt = standardSalt.length;
+        }
+        else
+        {
+            kParam = (RSAKeyParameters)param;
+            if (forSigning)
+            {
+                random = new SecureRandom();
+            }
+        }
+        
+        cipher.init(forSigning, kParam);
+
+        keyBits = kParam.getModulus().bitLength();
+
+        block = new byte[(keyBits + 7) / 8];
+        
+        if (trailer == TRAILER_IMPLICIT)
+        {
+            mBuf = new byte[block.length - digest.getDigestSize() - lengthOfSalt - 1 - 1];
+        }
+        else
+        {
+            mBuf = new byte[block.length - digest.getDigestSize() - lengthOfSalt - 1 - 2];
+        }
+
+        reset();
+    }
+
+    /**
+     * compare two byte arrays.
+     */
+    private boolean isSameAs(
+        byte[]    a,
+        byte[]    b)
+    {
+        if (messageLength != b.length)
+        {
+            return false;
+        }
+        
+        for (int i = 0; i != b.length; i++)
+        {
+            if (a[i] != b[i])
+            {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+    
+    /**
+     * clear possible sensitive data
+     */
+    private void clearBlock(
+        byte[]  block)
+    {
+        for (int i = 0; i != block.length; i++)
+        {
+            block[i] = 0;
+        }
+    }
+
+    /**
+     * update the internal digest with the byte b
+     */
+    public void update(
+        byte    b)
+    {
+        if (messageLength < mBuf.length)
+        {
+            mBuf[messageLength++] = b;
+        }
+        else
+        {
+            digest.update(b);
+        }
+    }
+
+    /**
+     * update the internal digest with the byte array in
+     */
+    public void update(
+        byte[]  in,
+        int     off,
+        int     len)
+    {
+        while (len > 0 && messageLength < mBuf.length)
+        {
+            this.update(in[off]);
+            off++;
+            len--;
+        }
+        
+        if (len > 0)
+        {
+            digest.update(in, off, len);
+        }
+    }
+
+    /**
+     * reset the internal state
+     */
+    public void reset()
+    {
+        digest.reset();
+        messageLength = 0;
+        if (recoveredMessage != null)
+        {
+            clearBlock(recoveredMessage);
+        }
+        recoveredMessage = null;
+        fullMessage = false;
+    }
+
+    /**
+     * generate a signature for the loaded message using the key we were
+     * initialised with.
+     */
+    public byte[] generateSignature()
+        throws CryptoException
+    {
+        int     digSize = digest.getDigestSize();
+
+        byte[]    m2Hash = new byte[digSize];
+  
+        digest.doFinal(m2Hash, 0);
+
+        byte[]  C = new byte[8];
+        LtoOSP(messageLength * 8, C);
+
+        digest.update(C, 0, C.length);
+
+        digest.update(mBuf, 0, messageLength);
+        
+        digest.update(m2Hash, 0, m2Hash.length);
+        
+        byte[]    salt;
+        
+        if (standardSalt != null)
+        {
+            salt = standardSalt;
+        }
+        else
+        {
+            salt = new byte[saltLength];
+            random.nextBytes(salt);
+        }
+        
+        digest.update(salt, 0, salt.length);
+
+        byte[]    hash = new byte[digest.getDigestSize()];
+        
+        digest.doFinal(hash, 0);
+        
+        int tLength = 2;
+        if (trailer == TRAILER_IMPLICIT)
+        {
+            tLength = 1;
+        }
+        
+        int    off = block.length - messageLength - salt.length - hLen - tLength - 1;
+        
+        block[off] = 0x01;
+  
+        System.arraycopy(mBuf, 0, block, off + 1, messageLength);
+        System.arraycopy(salt, 0, block, off + 1 + messageLength, salt.length);
+
+        byte[] dbMask = maskGeneratorFunction1(hash, 0, hash.length, block.length - hLen - tLength);
+        for (int i = 0; i != dbMask.length; i++)
+        {
+            block[i] ^= dbMask[i];
+        }
+        
+        System.arraycopy(hash, 0, block, block.length - hLen - tLength, hLen);
+        
+        if (trailer == TRAILER_IMPLICIT)
+        {
+            block[block.length - 1] = (byte)TRAILER_IMPLICIT;
+        }
+        else
+        {
+            block[block.length - 2] = (byte)(trailer >>> 8);
+            block[block.length - 1] = (byte)trailer;
+        }
+        
+        block[0] &= 0x7f;
+
+        byte[]  b = cipher.processBlock(block, 0, block.length);
+
+        clearBlock(mBuf);
+        clearBlock(block);
+        messageLength = 0;
+
+        return b;
+    }
+
+    /**
+     * return true if the signature represents a ISO9796-2 signature
+     * for the passed in message.
+     */
+    public boolean verifySignature(
+        byte[]      signature)
+    {
+        byte[]      block = null;
+
+        try
+        {
+            block = cipher.processBlock(signature, 0, signature.length);
+        }
+        catch (Exception e)
+        {
+            return false;
+        }
+        
+        //
+        // adjust block size for leading zeroes if necessary
+        //
+        if (block.length < (keyBits + 7) / 8)
+        {
+            byte[] tmp = new byte[(keyBits + 7) / 8];
+
+            System.arraycopy(block, 0, tmp, tmp.length - block.length, block.length);
+            block = tmp;
+        }
+
+        int     tLength = 0;
+
+        if (((block[block.length - 1] & 0xFF) ^ 0xBC) == 0)
+        {
+            tLength = 1;
+        }
+        else
+        {
+            int sigTrail = ((block[block.length - 2] & 0xFF) << 8) | (block[block.length - 1] & 0xFF);
+
+            switch (sigTrail)
+            {
+            // BEGIN android-removed
+            // case TRAILER_RIPEMD160:
+            //         if (!(digest instanceof RIPEMD160Digest))
+            //         {
+            //             throw new IllegalStateException("signer should be initialised with RIPEMD160");
+            //         }
+            //         break;
+            // END android-removed
+            case TRAILER_SHA1:
+                    if (!(digest instanceof SHA1Digest))
+                    {
+                        throw new IllegalStateException("signer should be initialised with SHA1");
+                    }
+                    break;
+            // BEGIN android-removed
+            // case TRAILER_RIPEMD128:
+            //         if (!(digest instanceof RIPEMD128Digest))
+            //         {
+            //             throw new IllegalStateException("signer should be initialised with RIPEMD128");
+            //         }
+            //        break;
+            // END android-removed
+            default:
+                throw new IllegalArgumentException("unrecognised hash in signature");
+            }
+
+            tLength = 2;
+        }
+
+        //
+        // calculate H(m2)
+        //
+        byte[]    m2Hash = new byte[hLen];
+        digest.doFinal(m2Hash, 0);
+        
+        //
+        // remove the mask
+        //
+        byte[] dbMask = maskGeneratorFunction1(block, block.length - hLen - tLength, hLen, block.length - hLen - tLength);
+        for (int i = 0; i != dbMask.length; i++)
+        {
+            block[i] ^= dbMask[i];
+        }
+
+        block[0] &= 0x7f;
+        
+        //
+        // find out how much padding we've got
+        //
+        int mStart = 0;
+
+        for (mStart = 0; mStart != block.length; mStart++)
+        {
+            if (block[mStart] == 0x01)
+            {
+                break;
+            }
+        }
+
+        mStart++;
+
+        if (mStart >= block.length)
+        {
+            clearBlock(block);
+            return false;
+        }
+        
+        if (mStart > 1)
+        {
+            fullMessage = true;
+        }
+        else
+        {
+            fullMessage = false;
+        }
+        
+        recoveredMessage = new byte[dbMask.length - mStart - saltLength];
+
+        System.arraycopy(block, mStart, recoveredMessage, 0, recoveredMessage.length);
+
+        //
+        // check the hashes
+        //
+        byte[]  C = new byte[8];
+        LtoOSP(recoveredMessage.length * 8, C);
+        
+        digest.update(C, 0, C.length);
+
+        if (recoveredMessage.length != 0)
+        {
+            digest.update(recoveredMessage, 0, recoveredMessage.length);
+        }
+
+        digest.update(m2Hash, 0, m2Hash.length);
+        byte[]  hash = new byte[digest.getDigestSize()];
+
+        digest.update(block, mStart + recoveredMessage.length, dbMask.length - mStart - recoveredMessage.length);
+        
+        digest.doFinal(hash, 0);
+
+        int off = block.length - tLength - hash.length;
+        
+        for (int i = 0; i != hash.length; i++)
+        {
+            if (hash[i] != block[off + i])
+            {
+                clearBlock(block);
+                clearBlock(hash);
+                clearBlock(recoveredMessage);
+                fullMessage = false;
+                
+                return false;
+            }
+        }
+
+        //
+        // if they've input a message check what we've recovered against
+        // what was input.
+        //
+        if (messageLength != 0)
+        {
+            if (!isSameAs(mBuf, recoveredMessage))
+            {
+                clearBlock(mBuf);
+                clearBlock(block);
+               
+                return false;
+            }
+        }
+        
+        clearBlock(mBuf);
+        clearBlock(block);
+        messageLength = 0;
+
+        return true;
+    }
+
+    /**
+     * Return true if the full message was recoveredMessage.
+     * 
+     * @return true on full message recovery, false otherwise, or if not sure.
+     * @see org.bouncycastle.crypto.SignerWithRecovery#hasFullMessage()
+     */
+    public boolean hasFullMessage()
+    {
+        return fullMessage;
+    }
+
+    /**
+     * Return a reference to the recoveredMessage message.
+     * 
+     * @return the full/partial recoveredMessage message.
+     * @see org.bouncycastle.crypto.SignerWithRecovery#getRecoveredMessage()
+     */
+    public byte[] getRecoveredMessage()
+    {
+        return recoveredMessage;
+    }
+    
+    /**
+     * int to octet string.
+     */
+    private void ItoOSP(
+        int     i,
+        byte[]  sp)
+    {
+        sp[0] = (byte)(i >>> 24);
+        sp[1] = (byte)(i >>> 16);
+        sp[2] = (byte)(i >>> 8);
+        sp[3] = (byte)(i >>> 0);
+    }
+
+    /**
+     * long to octet string.
+     */
+    private void LtoOSP(
+        long    l,
+        byte[]  sp)
+    {
+        sp[0] = (byte)(l >>> 56);
+        sp[1] = (byte)(l >>> 48);
+        sp[2] = (byte)(l >>> 40);
+        sp[3] = (byte)(l >>> 32);
+        sp[4] = (byte)(l >>> 24);
+        sp[5] = (byte)(l >>> 16);
+        sp[6] = (byte)(l >>> 8);
+        sp[7] = (byte)(l >>> 0);
+    }
+    /**
+     * mask generator function, as described in PKCS1v2.
+     */
+    private byte[] maskGeneratorFunction1(
+        byte[]  Z,
+        int     zOff,
+        int     zLen,
+        int     length)
+    {
+        byte[]  mask = new byte[length];
+        byte[]  hashBuf = new byte[hLen];
+        byte[]  C = new byte[4];
+        int     counter = 0;
+
+        digest.reset();
+
+        while (counter < (length / hLen))
+        {
+            ItoOSP(counter, C);
+
+            digest.update(Z, zOff, zLen);
+            digest.update(C, 0, C.length);
+            digest.doFinal(hashBuf, 0);
+
+            System.arraycopy(hashBuf, 0, mask, counter * hLen, hLen);
+            
+            counter++;
+        }
+
+        if ((counter * hLen) < length)
+        {
+            ItoOSP(counter, C);
+
+            digest.update(Z, zOff, zLen);
+            digest.update(C, 0, C.length);
+            digest.doFinal(hashBuf, 0);
+
+            System.arraycopy(hashBuf, 0, mask, counter * hLen, mask.length - (counter * hLen));
+        }
+
+        return mask;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/signers/ISO9796d2Signer.java b/libcore/security/src/main/java/org/bouncycastle/crypto/signers/ISO9796d2Signer.java
new file mode 100644
index 0000000..43e3017
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/signers/ISO9796d2Signer.java
@@ -0,0 +1,495 @@
+package org.bouncycastle.crypto.signers;
+
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.CryptoException;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.SignerWithRecovery;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.RIPEMD128Digest;
+// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
+// END android-removed
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+
+/**
+ * ISO9796-2 - mechanism using a hash function with recovery (scheme 1)
+ */
+public class ISO9796d2Signer
+    implements SignerWithRecovery
+{
+    static final public int   TRAILER_IMPLICIT    = 0xBC;
+    static final public int   TRAILER_RIPEMD160   = 0x31CC;
+    static final public int   TRAILER_RIPEMD128   = 0x32CC;
+    static final public int   TRAILER_SHA1        = 0x33CC;
+
+    private Digest                      digest;
+    private AsymmetricBlockCipher       cipher;
+
+    private int         trailer;
+    private int         keyBits;
+    private byte[]      block;
+    private byte[]      mBuf;
+    private int         messageLength;
+    private boolean     fullMessage;
+    private byte[]      recoveredMessage;
+
+    /**
+     * Generate a signer for the with either implicit or explicit trailers
+     * for ISO9796-2.
+     * 
+     * @param cipher base cipher to use for signature creation/verification
+     * @param digest digest to use.
+     * @param implicit whether or not the trailer is implicit or gives the hash.
+     */
+    public ISO9796d2Signer(
+        AsymmetricBlockCipher   cipher,
+        Digest                  digest,
+        boolean                 implicit)
+    {
+        this.cipher = cipher;
+        this.digest = digest;
+
+        if (implicit)
+        {
+            trailer = TRAILER_IMPLICIT;
+        }
+        else
+        {
+            if (digest instanceof SHA1Digest)
+            {
+                trailer = TRAILER_SHA1;
+            }
+            // BEGIN android-removed
+            // else if (digest instanceof RIPEMD160Digest)
+            // {
+            //     trailer = TRAILER_RIPEMD160;
+            // }
+            // else if (digest instanceof RIPEMD128Digest)
+            // {
+            //     trailer = TRAILER_RIPEMD128;
+            // }
+            // END android-removed
+            else
+            {
+                throw new IllegalArgumentException("no valid trailer for digest");
+            }
+        }
+    }
+
+    /**
+     * Constructor for a signer with an explicit digest trailer.
+     * 
+     * @param cipher cipher to use.
+     * @param digest digest to sign with.
+     */
+    public ISO9796d2Signer(
+        AsymmetricBlockCipher   cipher,
+        Digest                  digest)
+    {
+        this(cipher, digest, false);
+    }
+    
+    public void init(
+        boolean                 forSigning,
+        CipherParameters        param)
+    {
+        RSAKeyParameters  kParam = (RSAKeyParameters)param;
+
+        cipher.init(forSigning, kParam);
+
+        keyBits = kParam.getModulus().bitLength();
+
+        block = new byte[(keyBits + 7) / 8];
+        
+        if (trailer == TRAILER_IMPLICIT)
+        {
+            mBuf = new byte[block.length - digest.getDigestSize() - 2];
+        }
+        else
+        {
+            mBuf = new byte[block.length - digest.getDigestSize() - 3];
+        }
+
+        reset();
+    }
+
+    /**
+     * compare two byte arrays.
+     */
+    private boolean isSameAs(
+        byte[]    a,
+        byte[]    b)
+    {
+        if (messageLength > mBuf.length)
+        {
+            if (mBuf.length > b.length)
+            {
+                return false;
+            }
+            
+            for (int i = 0; i != mBuf.length; i++)
+            {
+                if (a[i] != b[i])
+                {
+                    return false;
+                }
+            }
+        }
+        else
+        {
+            if (messageLength != b.length)
+            {
+                return false;
+            }
+            
+            for (int i = 0; i != b.length; i++)
+            {
+                if (a[i] != b[i])
+                {
+                    return false;
+                }
+            }
+        }
+        
+        return true;
+    }
+    
+    /**
+     * clear possible sensitive data
+     */
+    private void clearBlock(
+        byte[]  block)
+    {
+        for (int i = 0; i != block.length; i++)
+        {
+            block[i] = 0;
+        }
+    }
+
+    /**
+     * update the internal digest with the byte b
+     */
+    public void update(
+        byte    b)
+    {
+        digest.update(b);
+
+        if (messageLength < mBuf.length)
+        {
+            mBuf[messageLength] = b;
+        }
+
+        messageLength++;
+    }
+
+    /**
+     * update the internal digest with the byte array in
+     */
+    public void update(
+        byte[]  in,
+        int     off,
+        int     len)
+    {
+        digest.update(in, off, len);
+
+        if (messageLength < mBuf.length)
+        {
+            for (int i = 0; i < len && (i + messageLength) < mBuf.length; i++)
+            {
+                mBuf[messageLength + i] = in[off + i];
+            }
+        }
+
+        messageLength += len;
+    }
+
+    /**
+     * reset the internal state
+     */
+    public void reset()
+    {
+        digest.reset();
+        messageLength = 0;
+        clearBlock(mBuf);
+        
+        if (recoveredMessage != null)
+        {
+            clearBlock(recoveredMessage);
+        }
+        
+        recoveredMessage = null;
+        fullMessage = false;
+    }
+
+    /**
+     * generate a signature for the loaded message using the key we were
+     * initialised with.
+     */
+    public byte[] generateSignature()
+        throws CryptoException
+    {
+        int     digSize = digest.getDigestSize();
+
+        int t = 0;
+        int delta = 0;
+
+        if (trailer == TRAILER_IMPLICIT)
+        {
+            t = 8;
+            delta = block.length - digSize - 1;
+            digest.doFinal(block, delta);
+            block[block.length - 1] = (byte)TRAILER_IMPLICIT;
+        }
+        else
+        {
+            t = 16;
+            delta = block.length - digSize - 2;
+            digest.doFinal(block, delta);
+            block[block.length - 2] = (byte)(trailer >>> 8);
+            block[block.length - 1] = (byte)trailer;
+        }
+
+        byte    header = 0;
+        int     x = (digSize + messageLength) * 8 + t + 4 - keyBits;
+
+        if (x > 0)
+        {
+            int mR = messageLength - ((x + 7) / 8);
+            header = 0x60;
+
+            delta -= mR;
+            
+            System.arraycopy(mBuf, 0, block, delta, mR);
+        }
+        else
+        {
+            header = 0x40;
+            delta -= messageLength;
+            
+            System.arraycopy(mBuf, 0, block, delta, messageLength);
+        }
+        
+        if ((delta - 1) > 0)
+        {
+            for (int i = delta - 1; i != 0; i--)
+            {
+                block[i] = (byte)0xbb;
+            }
+            block[delta - 1] ^= (byte)0x01;
+            block[0] = (byte)0x0b;
+            block[0] |= header;
+        }
+        else
+        {
+            block[0] = (byte)0x0a;
+            block[0] |= header;
+        }
+
+        byte[]  b = cipher.processBlock(block, 0, block.length);
+
+        clearBlock(mBuf);
+        clearBlock(block);
+
+        return b;
+    }
+
+    /**
+     * return true if the signature represents a ISO9796-2 signature
+     * for the passed in message.
+     */
+    public boolean verifySignature(
+        byte[]      signature)
+    {
+        byte[]      block = null;
+
+        try
+        {
+            block = cipher.processBlock(signature, 0, signature.length);
+        }
+        catch (Exception e)
+        {
+            return false;
+        }
+
+        if (((block[0] & 0xC0) ^ 0x40) != 0)
+        {
+            clearBlock(mBuf);
+            clearBlock(block);
+
+            return false;
+        }
+
+        if (((block[block.length - 1] & 0xF) ^ 0xC) != 0)
+        {
+            clearBlock(mBuf);
+            clearBlock(block);
+
+            return false;
+        }
+
+        int     delta = 0;
+
+        if (((block[block.length - 1] & 0xFF) ^ 0xBC) == 0)
+        {
+            delta = 1;
+        }
+        else
+        {
+            int sigTrail = ((block[block.length - 2] & 0xFF) << 8) | (block[block.length - 1] & 0xFF);
+
+            switch (sigTrail)
+            {
+            // BEGIN android-removed
+            // case TRAILER_RIPEMD160:
+            //         if (!(digest instanceof RIPEMD160Digest))
+            //         {
+            //             throw new IllegalStateException("signer should be initialised with RIPEMD160");
+            //         }
+            //         break;
+            // END android-removed
+            case TRAILER_SHA1:
+                    if (!(digest instanceof SHA1Digest))
+                    {
+                        throw new IllegalStateException("signer should be initialised with SHA1");
+                    }
+                    break;
+            // BEGIN android-removed
+            // case TRAILER_RIPEMD128:
+            //         if (!(digest instanceof RIPEMD128Digest))
+            //         {
+            //             throw new IllegalStateException("signer should be initialised with RIPEMD128");
+            //         }
+            //         break;
+            // END android-removed
+            default:
+                throw new IllegalArgumentException("unrecognised hash in signature");
+            }
+
+            delta = 2;
+        }
+
+        //
+        // find out how much padding we've got
+        //
+        int mStart = 0;
+
+        for (mStart = 0; mStart != block.length; mStart++)
+        {
+            if (((block[mStart] & 0x0f) ^ 0x0a) == 0)
+            {
+                break;
+            }
+        }
+
+        mStart++;
+
+        //
+        // check the hashes
+        //
+        byte[]  hash = new byte[digest.getDigestSize()];
+
+        int off = block.length - delta - hash.length;
+
+        //
+        // there must be at least one byte of message string
+        //
+        if ((off - mStart) <= 0)
+        {
+            clearBlock(mBuf);
+            clearBlock(block);
+
+            return false;
+        }
+
+        //
+        // if we contain the whole message as well, check the hash of that.
+        //
+        if ((block[0] & 0x20) == 0)
+        {
+            fullMessage = true;
+            
+            digest.reset();
+            digest.update(block, mStart, off - mStart);
+            digest.doFinal(hash, 0);
+            
+            for (int i = 0; i != hash.length; i++)
+            {
+                block[off + i] ^= hash[i];
+                if (block[off + i] != 0)
+                {
+                    clearBlock(mBuf);
+                    clearBlock(block);
+
+                    return false;
+                }
+            }
+            
+            recoveredMessage = new byte[off - mStart];
+            System.arraycopy(block, mStart, recoveredMessage, 0, recoveredMessage.length);
+        }
+        else
+        {
+            fullMessage = false;
+            
+            digest.doFinal(hash, 0);
+            
+            for (int i = 0; i != hash.length; i++)
+            {
+                block[off + i] ^= hash[i];
+                if (block[off + i] != 0)
+                {
+                    clearBlock(mBuf);
+                    clearBlock(block);
+
+                    return false;
+                }
+            }
+            
+            recoveredMessage = new byte[off - mStart];
+            System.arraycopy(block, mStart, recoveredMessage, 0, recoveredMessage.length);
+        }
+
+        //
+        // if they've input a message check what we've recovered against
+        // what was input.
+        //
+        if (messageLength != 0)
+        {
+            if (!isSameAs(mBuf, recoveredMessage))
+            {
+                clearBlock(mBuf);
+                clearBlock(block);
+
+                return false;
+            }
+        }
+        
+        clearBlock(mBuf);
+        clearBlock(block);
+
+        return true;
+    }
+
+    /**
+     * Return true if the full message was recoveredMessage.
+     * 
+     * @return true on full message recovery, false otherwise.
+     * @see org.bouncycastle.crypto.SignerWithRecovery#hasFullMessage()
+     */
+    public boolean hasFullMessage()
+    {
+        return fullMessage;
+    }
+
+    /**
+     * Return a reference to the recoveredMessage message.
+     * 
+     * @return the full/partial recoveredMessage message.
+     * @see org.bouncycastle.crypto.SignerWithRecovery#getRecoveredMessage()
+     */
+    public byte[] getRecoveredMessage()
+    {
+        return recoveredMessage;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/signers/PSSSigner.java b/libcore/security/src/main/java/org/bouncycastle/crypto/signers/PSSSigner.java
new file mode 100644
index 0000000..ad4f53e
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/signers/PSSSigner.java
@@ -0,0 +1,318 @@
+package org.bouncycastle.crypto.signers;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.CryptoException;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.Signer;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+
+/**
+ * RSA-PSS as described in PKCS# 1 v 2.1.
+ * <p>
+ * Note: the usual value for the salt length is the number of
+ * bytes in the hash function.
+ */
+public class PSSSigner
+    implements Signer
+{
+    static final public byte   TRAILER_IMPLICIT    = (byte)0xBC;
+
+    private Digest                      digest;
+    private AsymmetricBlockCipher       cipher;
+    private SecureRandom                random;
+
+    private int                         hLen;
+    private int                         sLen;
+    private int                         emBits;
+    private byte[]                      salt;
+    private byte[]                      mDash;
+    private byte[]                      block;
+    private byte                        trailer;
+
+    /**
+     * basic constructor
+     *
+     * @param cipher the assymetric cipher to use.
+     * @param digest the digest to use.
+     * @param sLen the length of the salt to use (in bytes).
+     */
+    public PSSSigner(
+        AsymmetricBlockCipher   cipher,
+        Digest                  digest,
+        int                     sLen)
+    {
+        this(cipher, digest, sLen, TRAILER_IMPLICIT);
+    }
+    
+    public PSSSigner(
+        AsymmetricBlockCipher   cipher,
+        Digest                  digest,
+        int                     sLen,
+        byte                    trailer)
+    {
+        this.cipher = cipher;
+        this.digest = digest;
+        this.hLen = digest.getDigestSize();
+        this.sLen = sLen;
+        this.salt = new byte[sLen];
+        this.mDash = new byte[8 + sLen + hLen];
+        this.trailer = trailer;
+    }
+
+    public void init(
+        boolean                 forSigning,
+        CipherParameters        param)
+    {
+        RSAKeyParameters  kParam = null;
+
+        if (param instanceof ParametersWithRandom)
+        {
+            ParametersWithRandom    p = (ParametersWithRandom)param;
+
+            kParam = (RSAKeyParameters)p.getParameters();
+            random = p.getRandom();
+        }
+        else
+        {
+            kParam = (RSAKeyParameters)param;
+            if (forSigning)
+            {
+                random = new SecureRandom();
+            }
+        }
+
+        cipher.init(forSigning, kParam);
+
+        emBits = kParam.getModulus().bitLength() - 1;
+
+        block = new byte[(emBits + 7) / 8];
+
+        reset();
+    }
+
+    /**
+     * clear possible sensitive data
+     */
+    private void clearBlock(
+        byte[]  block)
+    {
+        for (int i = 0; i != block.length; i++)
+        {
+            block[i] = 0;
+        }
+    }
+
+    /**
+     * update the internal digest with the byte b
+     */
+    public void update(
+        byte    b)
+    {
+        digest.update(b);
+    }
+
+    /**
+     * update the internal digest with the byte array in
+     */
+    public void update(
+        byte[]  in,
+        int     off,
+        int     len)
+    {
+        digest.update(in, off, len);
+    }
+
+    /**
+     * reset the internal state
+     */
+    public void reset()
+    {
+        digest.reset();
+    }
+
+    /**
+     * generate a signature for the message we've been loaded with using
+     * the key we were initialised with.
+     */
+    public byte[] generateSignature()
+        throws CryptoException, DataLengthException
+    {
+        if (emBits < (8 * hLen + 8 * sLen + 9))
+        {
+            throw new DataLengthException("encoding error");
+        }
+
+        digest.doFinal(mDash, mDash.length - hLen - sLen);
+
+        if (sLen != 0)
+        {
+            random.nextBytes(salt);
+
+            System.arraycopy(salt, 0, mDash, mDash.length - sLen, sLen);
+        }
+
+        byte[]  h = new byte[hLen];
+
+        digest.update(mDash, 0, mDash.length);
+
+        digest.doFinal(h, 0);
+
+        block[block.length - sLen - 1 - hLen - 1] = 0x01;
+        System.arraycopy(salt, 0, block, block.length - sLen - hLen - 1, sLen);
+
+        byte[] dbMask = maskGeneratorFunction1(h, 0, h.length, block.length - hLen - 1);
+        for (int i = 0; i != dbMask.length; i++)
+        {
+            block[i] ^= dbMask[i];
+        }
+
+        block[0] &= (0xff >> ((block.length * 8) - emBits));
+
+        System.arraycopy(h, 0, block, block.length - hLen - 1, hLen);
+
+        block[block.length - 1] = trailer;
+
+        byte[]  b = cipher.processBlock(block, 0, block.length);
+
+        clearBlock(block);
+
+        return b;
+    }
+
+    /**
+     * return true if the internal state represents the signature described
+     * in the passed in array.
+     */
+    public boolean verifySignature(
+        byte[]      signature)
+    {
+        if (emBits < (8 * hLen + 8 * sLen + 9))
+        {
+            return false;
+        }
+
+        digest.doFinal(mDash, mDash.length - hLen - sLen);
+
+        try
+        {
+            byte[] b = cipher.processBlock(signature, 0, signature.length);
+            System.arraycopy(b, 0, block, block.length - b.length, b.length);
+        }
+        catch (Exception e)
+        {
+            return false;
+        }
+
+        if (block[block.length - 1] != trailer)
+        {
+            clearBlock(block);
+            return false;
+        }
+
+        byte[] dbMask = maskGeneratorFunction1(block, block.length - hLen - 1, hLen, block.length - hLen - 1);
+
+        for (int i = 0; i != dbMask.length; i++)
+        {
+            block[i] ^= dbMask[i];
+        }
+
+        block[0] &= (0xff >> ((block.length * 8) - emBits));
+
+        for (int i = 0; i != block.length - hLen - sLen - 2; i++)
+        {
+            if (block[i] != 0)
+            {
+                clearBlock(block);
+                return false;
+            }
+        }
+
+        if (block[block.length - hLen - sLen - 2] != 0x01)
+        {
+            clearBlock(block);
+            return false;
+        }
+
+        System.arraycopy(block, block.length - sLen - hLen - 1, mDash, mDash.length - sLen, sLen);
+
+        digest.update(mDash, 0, mDash.length);
+        digest.doFinal(mDash, mDash.length - hLen);
+
+        for (int i = block.length - hLen - 1, j = mDash.length - hLen;
+                                                 j != mDash.length; i++, j++)
+        {
+            if ((block[i] ^ mDash[j]) != 0)
+            {
+                clearBlock(mDash);
+                clearBlock(block);
+                return false;
+            }
+        }
+
+        clearBlock(mDash);
+        clearBlock(block);
+
+        return true;
+    }
+
+    /**
+     * int to octet string.
+     */
+    private void ItoOSP(
+        int     i,
+        byte[]  sp)
+    {
+        sp[0] = (byte)(i >>> 24);
+        sp[1] = (byte)(i >>> 16);
+        sp[2] = (byte)(i >>> 8);
+        sp[3] = (byte)(i >>> 0);
+    }
+
+    /**
+     * mask generator function, as described in PKCS1v2.
+     */
+    private byte[] maskGeneratorFunction1(
+        byte[]  Z,
+        int     zOff,
+        int     zLen,
+        int     length)
+    {
+        byte[]  mask = new byte[length];
+        byte[]  hashBuf = new byte[hLen];
+        byte[]  C = new byte[4];
+        int     counter = 0;
+
+        digest.reset();
+
+        while (counter < (length / hLen))
+        {
+            ItoOSP(counter, C);
+
+            digest.update(Z, zOff, zLen);
+            digest.update(C, 0, C.length);
+            digest.doFinal(hashBuf, 0);
+
+            System.arraycopy(hashBuf, 0, mask, counter * hLen, hLen);
+            
+            counter++;
+        }
+
+        if ((counter * hLen) < length)
+        {
+            ItoOSP(counter, C);
+
+            digest.update(Z, zOff, zLen);
+            digest.update(C, 0, C.length);
+            digest.doFinal(hashBuf, 0);
+
+            System.arraycopy(hashBuf, 0, mask, counter * hLen, mask.length - (counter * hLen));
+        }
+
+        return mask;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java b/libcore/security/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
new file mode 100644
index 0000000..bb14375
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
@@ -0,0 +1,136 @@
+package org.bouncycastle.crypto.util;
+
+import java.io.IOException;
+
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.oiw.ElGamalParameter;
+// END android-removed
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.DHParameter;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.sec.ECPrivateKeyStructure;
+// END android-removed
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.DSAParameter;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.x9.X962NamedCurves;
+// import org.bouncycastle.asn1.x9.X962Parameters;
+// import org.bouncycastle.asn1.x9.X9ECParameters;
+// END android-removed
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.DHParameters;
+import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import org.bouncycastle.crypto.params.DSAParameters;
+import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.params.ECDomainParameters;
+// import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+// import org.bouncycastle.crypto.params.ElGamalParameters;
+// import org.bouncycastle.crypto.params.ElGamalPrivateKeyParameters;
+//END android-removed
+import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+
+/**
+ * Factory for creating private key objects from PKCS8 PrivateKeyInfo objects.
+ */
+public class PrivateKeyFactory
+{
+    /**
+     * Create a private key parameter from the passed in PKCS8 PrivateKeyInfo object.
+     * 
+     * @param keyInfo the PrivateKeyInfo object containing the key material
+     * @return a suitable private key parameter
+     * @throws IOException on an error decoding the key
+     */
+    public static AsymmetricKeyParameter createKey(
+        PrivateKeyInfo    keyInfo)
+        throws IOException
+    {
+        AlgorithmIdentifier     algId = keyInfo.getAlgorithmId();
+        
+        if (algId.getObjectId().equals(PKCSObjectIdentifiers.rsaEncryption))
+        {
+            RSAPrivateKeyStructure  keyStructure = new RSAPrivateKeyStructure((ASN1Sequence)keyInfo.getPrivateKey());
+
+            return new RSAPrivateCrtKeyParameters(
+                                        keyStructure.getModulus(),
+                                        keyStructure.getPublicExponent(),
+                                        keyStructure.getPrivateExponent(),
+                                        keyStructure.getPrime1(),
+                                        keyStructure.getPrime2(),
+                                        keyStructure.getExponent1(),
+                                        keyStructure.getExponent2(),
+                                        keyStructure.getCoefficient());
+        }
+        else if (algId.getObjectId().equals(PKCSObjectIdentifiers.dhKeyAgreement))
+        {
+            DHParameter     params = new DHParameter((ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
+            DERInteger      derX = (DERInteger)keyInfo.getPrivateKey();
+
+            return new DHPrivateKeyParameters(derX.getValue(), new DHParameters(params.getP(), params.getG()));
+        }
+        // BEGIN android-removed
+        // else if (algId.getObjectId().equals(OIWObjectIdentifiers.elGamalAlgorithm))
+        // {
+        //     ElGamalParameter    params = new ElGamalParameter((ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
+        //     DERInteger          derX = (DERInteger)keyInfo.getPrivateKey();
+        //
+        //     return new ElGamalPrivateKeyParameters(derX.getValue(), new ElGamalParameters(params.getP(), params.getG()));
+        // }
+        // END android-removed
+        else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_dsa))
+        {
+            DSAParameter    params = new DSAParameter((ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
+            DERInteger      derX = (DERInteger)keyInfo.getPrivateKey();
+
+            return new DSAPrivateKeyParameters(derX.getValue(), new DSAParameters(params.getP(), params.getQ(), params.getG()));
+        }
+        // BEGIN android-removed
+        // else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_ecPublicKey))
+        // {
+        //     X962Parameters      params = new X962Parameters((DERObject)keyInfo.getAlgorithmId().getParameters());
+        //     ECDomainParameters  dParams = null;
+        //    
+        //     if (params.isNamedCurve())
+        //     {
+        //         DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
+        //         X9ECParameters      ecP = X962NamedCurves.getByOID(oid);
+        //
+        //         dParams = new ECDomainParameters(
+        //                                     ecP.getCurve(),
+        //                                     ecP.getG(),
+        //                                     ecP.getN(),
+        //                                     ecP.getH(),
+        //                                     ecP.getSeed());
+        //     }
+        //     else
+        //     {
+        //         X9ECParameters ecP = new X9ECParameters(
+        //                     (ASN1Sequence)params.getParameters());
+        //         dParams = new ECDomainParameters(
+        //                                     ecP.getCurve(),
+        //                                     ecP.getG(),
+        //                                     ecP.getN(),
+        //                                     ecP.getH(),
+        //                                     ecP.getSeed());
+        //     }
+        //
+        //     ECPrivateKeyStructure   ec = new ECPrivateKeyStructure((ASN1Sequence)keyInfo.getPrivateKey());
+        //
+        //     return new ECPrivateKeyParameters(ec.getKey(), dParams);
+        // }
+        // END android-removed
+        else
+        {
+            throw new RuntimeException("algorithm identifier in key not recognised");
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java b/libcore/security/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
new file mode 100644
index 0000000..c666800
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
@@ -0,0 +1,138 @@
+package org.bouncycastle.crypto.util;
+
+import java.io.IOException;
+
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DEROctetString;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.oiw.ElGamalParameter;
+// END android-removed
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.DHParameter;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.DSAParameter;
+import org.bouncycastle.asn1.x509.RSAPublicKeyStructure;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.x9.X962NamedCurves;
+// import org.bouncycastle.asn1.x9.X962Parameters;
+// import org.bouncycastle.asn1.x9.X9ECParameters;
+// import org.bouncycastle.asn1.x9.X9ECPoint;
+// END android-removed
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.DHParameters;
+import org.bouncycastle.crypto.params.DHPublicKeyParameters;
+import org.bouncycastle.crypto.params.DSAParameters;
+import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.params.ECDomainParameters;
+// import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+// import org.bouncycastle.crypto.params.ElGamalParameters;
+// import org.bouncycastle.crypto.params.ElGamalPublicKeyParameters;
+// END android-removed
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+
+/**
+ * Factory to create asymmetric public key parameters for asymmetric ciphers
+ * from range of ASN.1 encoded SubjectPublicKeyInfo objects.
+ */
+public class PublicKeyFactory
+{
+    /**
+     * Create a public key from the passed in SubjectPublicKeyInfo
+     * 
+     * @param keyInfo the SubjectPublicKeyInfo containing the key data
+     * @return the appropriate key parameter
+     * @throws IOException on an error decoding the key
+     */
+    public static AsymmetricKeyParameter createKey(
+        SubjectPublicKeyInfo    keyInfo)
+        throws IOException
+    {
+        AlgorithmIdentifier     algId = keyInfo.getAlgorithmId();
+        
+        if (algId.getObjectId().equals(PKCSObjectIdentifiers.rsaEncryption)
+            || algId.getObjectId().equals(X509ObjectIdentifiers.id_ea_rsa))
+        {
+            RSAPublicKeyStructure   pubKey = new RSAPublicKeyStructure((ASN1Sequence)keyInfo.getPublicKey());
+
+            return new RSAKeyParameters(false, pubKey.getModulus(), pubKey.getPublicExponent());
+        }
+        else if (algId.getObjectId().equals(PKCSObjectIdentifiers.dhKeyAgreement)
+                 || algId.getObjectId().equals(X9ObjectIdentifiers.dhpublicnumber))
+        {
+            DHParameter params = new DHParameter((ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
+            DERInteger  derY = (DERInteger)keyInfo.getPublicKey();
+            
+            return new DHPublicKeyParameters(derY.getValue(), new DHParameters(params.getP(), params.getG()));
+        }
+        // BEGIN android-removed
+        // else if (algId.getObjectId().equals(OIWObjectIdentifiers.elGamalAlgorithm))
+        // {
+        //     ElGamalParameter    params = new ElGamalParameter((ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
+        //     DERInteger          derY = (DERInteger)keyInfo.getPublicKey();
+        //
+        //     return new ElGamalPublicKeyParameters(derY.getValue(), new ElGamalParameters(params.getP(), params.getG()));
+        // }
+        // END android-removed
+        else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_dsa)
+                 || algId.getObjectId().equals(OIWObjectIdentifiers.dsaWithSHA1))
+        {
+            DSAParameter    params = new DSAParameter((ASN1Sequence)keyInfo.getAlgorithmId().getParameters());
+            DERInteger      derY = (DERInteger)keyInfo.getPublicKey();
+
+            return new DSAPublicKeyParameters(derY.getValue(), new DSAParameters(params.getP(), params.getQ(), params.getG()));
+        }
+        // BEGIN android-removed
+        // else if (algId.getObjectId().equals(X9ObjectIdentifiers.id_ecPublicKey))
+        // {
+        //     X962Parameters      params = new X962Parameters((DERObject)keyInfo.getAlgorithmId().getParameters());
+        //     ECDomainParameters  dParams = null;
+        //     
+        //     if (params.isNamedCurve())
+        //     {
+        //         DERObjectIdentifier oid = (DERObjectIdentifier)params.getParameters();
+        //         X9ECParameters      ecP = X962NamedCurves.getByOID(oid);
+        //
+        //         dParams = new ECDomainParameters(
+        //                                     ecP.getCurve(),
+        //                                     ecP.getG(),
+        //                                     ecP.getN(),
+        //                                     ecP.getH(),
+        //                                     ecP.getSeed());
+        //     }
+        //     else
+        //     {
+        //         X9ECParameters ecP = new X9ECParameters(
+        //                     (ASN1Sequence)params.getParameters());
+        //         dParams = new ECDomainParameters(
+        //                                     ecP.getCurve(),
+        //                                     ecP.getG(),
+        //                                     ecP.getN(),
+        //                                     ecP.getH(),
+        //                                     ecP.getSeed());
+        //     }
+        //
+        //     DERBitString    bits = keyInfo.getPublicKeyData();
+        //     byte[]          data = bits.getBytes();
+        //     ASN1OctetString key = new DEROctetString(data);
+        //
+        //     X9ECPoint       derQ = new X9ECPoint(dParams.getCurve(), key);
+        //    
+        //     return new ECPublicKeyParameters(derQ.getPoint(), dParams);
+        // }
+        // BEGIN android-removed
+        else
+        {
+            throw new RuntimeException("algorithm identifier in key not recognised");
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/i18n/ErrorBundle.java b/libcore/security/src/main/java/org/bouncycastle/i18n/ErrorBundle.java
new file mode 100644
index 0000000..803abed
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/i18n/ErrorBundle.java
@@ -0,0 +1,90 @@
+package org.bouncycastle.i18n;
+
+import java.util.Locale;
+import java.util.TimeZone;
+
+public class ErrorBundle extends MessageBundle 
+{
+
+    /**
+     * summary entry key
+     */
+    public static final String SUMMARY_ENTRY = "summary";
+    
+    /**
+     * detail entry key
+     */
+    public static final String DETAIL_ENTRY = "details";
+    
+    /**
+     * Constructs a new ErrorBundle using <code>resource</code> as the base name for the 
+     * RessourceBundle and <code>id</code> as the message bundle id the resource file. 
+     * @param resource base name of the resource file 
+     * @param id the id of the corresponding bundle in the resource file
+     * @throws NullPointerException if <code>resource</code> or <code>id</code> is <code>null</code>
+     */
+    public ErrorBundle(String resource, String id) throws NullPointerException
+    {
+        super(resource, id);
+    }
+
+    /**
+     * Constructs a new ErrorBundle using <code>resource</code> as the base name for the 
+     * RessourceBundle and <code>id</code> as the message bundle id the resource file. 
+     * @param resource base name of the resource file 
+     * @param id the id of the corresponding bundle in the resource file
+     * @param arguments an array containing the arguments for the message
+     * @throws NullPointerException if <code>resource</code> or <code>id</code> is <code>null</code>
+     */
+    public ErrorBundle(String resource, String id, Object[] arguments) throws NullPointerException
+    {
+        super(resource, id, arguments);
+    }
+    
+    /**
+     * Returns the summary message in the given locale and timezone.
+     * @param loc the {@link Locale}
+     * @param timezone the {@link TimeZone}
+     * @return the summary message.
+     * @throws MissingEntryException if the message is not available
+     */
+    public String getSummary(Locale loc, TimeZone timezone) throws MissingEntryException
+    {
+        return getEntry(SUMMARY_ENTRY,loc,timezone);
+    }
+    
+    /**
+     * Returns the summary message in the given locale and the default timezone.
+     * @param loc the {@link Locale}
+     * @return the summary message.
+     * @throws MissingEntryException if the message is not available
+     */
+    public String getSummary(Locale loc) throws MissingEntryException
+    {
+        return getEntry(SUMMARY_ENTRY,loc,TimeZone.getDefault());
+    }
+    
+    /**
+     * Returns the detail message in the given locale and timezone.
+     * @param loc the {@link Locale}
+     * @param timezone the {@link TimeZone}
+     * @return the detail message.
+     * @throws MissingEntryException if the message is not available
+     */
+    public String getDetail(Locale loc, TimeZone timezone) throws MissingEntryException
+    {
+        return getEntry(DETAIL_ENTRY,loc,timezone);
+    }
+    
+    /**
+     * Returns the detail message in the given locale and the default timezone.
+     * @param loc the {@link Locale}
+     * @return the detail message.
+     * @throws MissingEntryException if the message is not available
+     */
+    public String getDetail(Locale loc) throws MissingEntryException
+    {
+        return getEntry(DETAIL_ENTRY,loc,TimeZone.getDefault());
+    }
+
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/i18n/LocalizedException.java b/libcore/security/src/main/java/org/bouncycastle/i18n/LocalizedException.java
new file mode 100644
index 0000000..373fd6c
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/i18n/LocalizedException.java
@@ -0,0 +1,49 @@
+package org.bouncycastle.i18n;
+
+import java.util.Locale;
+
+/**
+ * Base class for all Exceptions with localized messages.
+ */
+public class LocalizedException extends Exception 
+{
+
+    protected ErrorBundle message;
+    private Throwable cause;
+    
+    /**
+     * Constructs a new LocalizedException with the specified localized message.
+     * @param message the {@link ErrorBundle} that contains the message for the exception
+     */
+    public LocalizedException(ErrorBundle message) 
+    {
+        super(message.getText(Locale.getDefault()));
+        this.message = message;
+    }
+    
+    /**
+     * Constructs a new LocalizedException with the specified localized message and cause.
+     * @param message the {@link ErrorBundle} that contains the message for the exception
+     * @param throwable the cause
+     */
+    public LocalizedException(ErrorBundle message, Throwable throwable) 
+    {
+        super(message.getText(Locale.getDefault()));
+        this.message = message;
+        this.cause = throwable;
+    }
+    
+    /**
+     * Returns the localized error message of the exception.
+     * @return the localized error message as {@link ErrorBundle}
+     */
+    public ErrorBundle getErrorMessage() 
+    {
+        return message;
+    }
+
+    public Throwable getCause()
+    {
+        return cause;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/i18n/LocalizedMessage.java b/libcore/security/src/main/java/org/bouncycastle/i18n/LocalizedMessage.java
new file mode 100644
index 0000000..b5ab60f
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/i18n/LocalizedMessage.java
@@ -0,0 +1,187 @@
+package org.bouncycastle.i18n;
+
+import java.text.DateFormat;
+import java.text.Format;
+import java.text.MessageFormat;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.TimeZone;
+
+import org.bouncycastle.i18n.filter.Filter;
+import org.bouncycastle.i18n.filter.UntrustedInput;
+
+public class LocalizedMessage 
+{
+
+    protected final String id;
+    protected final String resource;
+    
+    protected Object[] arguments;
+    protected Object[] filteredArguments;
+    
+    protected Filter filter = null;
+    
+    /**
+     * Constructs a new LocalizedMessage using <code>resource</code> as the base name for the 
+     * RessourceBundle and <code>id</code> as the message bundle id the resource file. 
+     * @param resource base name of the resource file 
+     * @param id the id of the corresponding bundle in the resource file
+     * @throws NullPointerException if <code>resource</code> or <code>id</code> is <code>null</code>
+     */
+    public LocalizedMessage(String resource,String id) throws NullPointerException
+    {
+        if (resource == null || id == null)
+        {
+            throw new NullPointerException();
+        }
+        this.id = id;
+        this.resource = resource;
+        this.arguments = new Object[0];
+        this.filteredArguments = arguments;
+    }
+    
+    /**
+     * Constructs a new LocalizedMessage using <code>resource</code> as the base name for the 
+     * RessourceBundle and <code>id</code> as the message bundle id the resource file. 
+     * @param resource base name of the resource file 
+     * @param id the id of the corresponding bundle in the resource file
+     * @param arguments an array containing the arguments for the message
+     * @throws NullPointerException if <code>resource</code> or <code>id</code> is <code>null</code>
+     */
+    public LocalizedMessage(String resource, String id, Object[] arguments) throws NullPointerException
+    {
+        if (resource == null || id == null || arguments == null)
+        {
+            throw new NullPointerException();
+        }
+        this.id = id;
+        this.resource = resource;
+        this.arguments = arguments;
+        this.filteredArguments = arguments;
+    }
+    
+    /**
+     * Reads the entry <code>id + "." + key</code> from the resource file and returns a 
+     * formated message for the given Locale and TimeZone.
+     * @param key second part of the entry id
+     * @param loc the used {@link Locale}
+     * @param timezone the used {@link TimeZone}
+     * @return a Strng containing the localized message
+     * @throws MissingEntryException if the resource file is not available or the entry does not exist.
+     */
+    public String getEntry(String key,Locale loc, TimeZone timezone) throws MissingEntryException
+    {
+        String entry = id + "." + key;
+        
+        try
+        {
+            ResourceBundle bundle = ResourceBundle.getBundle(resource,loc);
+            String template = bundle.getString(entry);
+            if (arguments == null || arguments.length == 0)
+            {
+                return template;
+            }
+            else
+            {
+                return formatWithTimeZone(template,filteredArguments,loc,timezone);
+            }
+        }
+        catch (MissingResourceException mre)
+        {
+            throw new MissingEntryException("Can't find entry " + entry + " in resource file " + resource + ".",
+                    resource,
+                    entry); 
+        }
+    }
+    
+    protected String formatWithTimeZone(
+            String template,
+            Object[] arguments, 
+            Locale locale,
+            TimeZone timezone) 
+    {
+        MessageFormat mf = new MessageFormat(" ");
+        mf.setLocale(locale);
+        mf.applyPattern(template);
+        if (!timezone.equals(TimeZone.getDefault())) 
+        {
+            Format[] formats = mf.getFormats();
+            for (int i = 0; i < formats.length; i++) 
+            {
+                if (formats[i] instanceof DateFormat) 
+                {
+                    DateFormat temp = (DateFormat) formats[i];
+                    temp.setTimeZone(timezone);
+                    mf.setFormat(i,temp);
+                }
+            }
+        }
+        return mf.format(arguments);
+    }
+    
+    /**
+     * Sets the {@link Filter} that is used to filter the arguments of this message
+     * @param filter the {@link Filter} to use. <code>null</code> to disable filtering.
+     */
+    public void setFilter(Filter filter)
+    {
+        if (filter == null)
+        {
+            filteredArguments = arguments;
+        }
+        else if (!filter.equals(this.filter))
+        {
+            filteredArguments = new Object[arguments.length];
+            for (int i = 0; i < arguments.length; i++)
+            {
+                if (arguments[i] instanceof UntrustedInput) 
+                {
+                    filteredArguments[i] = filter.doFilter(((UntrustedInput) arguments[i]).getString());
+                }
+                else
+                {
+                    filteredArguments[i] = arguments[i];
+                }
+            }
+        }
+        this.filter = filter;
+    }
+    
+    /**
+     * Returns the current filter.
+     * @return the current filter
+     */
+    public Filter getFilter()
+    {
+        return filter;
+    }
+    
+    /**
+     * Returns the id of the message in the resource bundle.
+     * @return the id of the message
+     */
+    public String getId()
+    {
+        return id;
+    }
+    
+    /**
+     * Returns the name of the resource bundle for this message
+     * @return name of the resource file
+     */
+    public String getResource()
+    {
+        return resource;
+    }
+    
+    /**
+     * Returns an <code>Object[]</code> containing the message arguments.
+     * @return the message arguments
+     */
+    public Object[] getArguments()
+    {
+        return arguments;
+    }
+    
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/i18n/MessageBundle.java b/libcore/security/src/main/java/org/bouncycastle/i18n/MessageBundle.java
new file mode 100644
index 0000000..8848f0f
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/i18n/MessageBundle.java
@@ -0,0 +1,62 @@
+package org.bouncycastle.i18n;
+
+import java.util.Locale;
+import java.util.TimeZone;
+
+public class MessageBundle extends TextBundle
+{
+
+    /**
+     * title entry key
+     */
+    public static final String TITLE_ENTRY = "title";
+    
+    /**
+     * Constructs a new MessageBundle using <code>resource</code> as the base name for the 
+     * RessourceBundle and <code>id</code> as the message bundle id the resource file. 
+     * @param resource base name of the resource file 
+     * @param id the id of the corresponding bundle in the resource file
+     * @throws NullPointerException if <code>resource</code> or <code>id</code> is <code>null</code>
+     */
+    public MessageBundle(String resource, String id) throws NullPointerException
+    {
+        super(resource, id);
+    }
+
+    /**
+     * Constructs a new MessageBundle using <code>resource</code> as the base name for the 
+     * RessourceBundle and <code>id</code> as the message bundle id the resource file. 
+     * @param resource base name of the resource file 
+     * @param id the id of the corresponding bundle in the resource file
+     * @param arguments an array containing the arguments for the message
+     * @throws NullPointerException if <code>resource</code> or <code>id</code> is <code>null</code>
+     */
+    public MessageBundle(String resource, String id, Object[] arguments) throws NullPointerException
+    {
+        super(resource, id, arguments);
+    }
+    
+    /**
+     * Returns the title message in the given locale and timezone.
+     * @param loc the {@link Locale}
+     * @param timezone the {@link TimeZone}
+     * @return the title message.
+     * @throws MissingEntryException if the message is not available
+     */
+    public String getTitle(Locale loc,TimeZone timezone) throws MissingEntryException
+    {
+        return getEntry(TITLE_ENTRY,loc,timezone);
+    }
+    
+    /**
+     * Returns the title message in the given locale and the default timezone.
+     * @param loc the {@link Locale}
+     * @return the title message.
+     * @throws MissingEntryException if the message is not available
+     */
+    public String getTitle(Locale loc) throws MissingEntryException
+    {
+        return getEntry(TITLE_ENTRY,loc,TimeZone.getDefault());
+    }
+
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/i18n/MissingEntryException.java b/libcore/security/src/main/java/org/bouncycastle/i18n/MissingEntryException.java
new file mode 100644
index 0000000..11dfdc4
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/i18n/MissingEntryException.java
@@ -0,0 +1,26 @@
+package org.bouncycastle.i18n;
+
+public class MissingEntryException extends RuntimeException 
+{
+
+    protected final String resource;
+    protected final String key;
+
+    public MissingEntryException(String message, String resource, String key) 
+    {
+        super(message);
+        this.resource = resource;
+        this.key = key;
+    }
+
+    public String getKey()
+    {
+        return key;
+    }
+
+    public String getResource()
+    {
+        return resource;
+    }
+
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/i18n/TextBundle.java b/libcore/security/src/main/java/org/bouncycastle/i18n/TextBundle.java
new file mode 100644
index 0000000..9d981d9
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/i18n/TextBundle.java
@@ -0,0 +1,62 @@
+package org.bouncycastle.i18n;
+
+import java.util.Locale;
+import java.util.TimeZone;
+
+public class TextBundle extends LocalizedMessage 
+{
+
+    /**
+     * text entry key
+     */
+    public static final String TEXT_ENTRY = "text";
+    
+    /**
+     * Constructs a new TextBundle using <code>resource</code> as the base name for the 
+     * RessourceBundle and <code>id</code> as the message bundle id the resource file. 
+     * @param resource base name of the resource file 
+     * @param id the id of the corresponding bundle in the resource file
+     * @throws NullPointerException if <code>resource</code> or <code>id</code> is <code>null</code>
+     */
+    public TextBundle(String resource, String id) throws NullPointerException 
+    {
+        super(resource, id);
+    }
+
+    /**
+     * Constructs a new TextBundle using <code>resource</code> as the base name for the 
+     * RessourceBundle and <code>id</code> as the message bundle id the resource file. 
+     * @param resource base name of the resource file 
+     * @param id the id of the corresponding bundle in the resource file
+     * @param arguments an array containing the arguments for the message
+     * @throws NullPointerException if <code>resource</code> or <code>id</code> is <code>null</code>
+     */
+    public TextBundle(String resource, String id, Object[] arguments) throws NullPointerException 
+    {
+        super(resource, id, arguments);
+    }
+    
+    /**
+     * Returns the text message in the given locale and timezone.
+     * @param loc the {@link Locale}
+     * @param timezone the {@link TimeZone}
+     * @return the text message.
+     * @throws MissingEntryException if the message is not available
+     */
+    public String getText(Locale loc, TimeZone timezone) throws MissingEntryException
+    {
+        return getEntry(TEXT_ENTRY,loc,timezone);
+    }
+    
+    /**
+     * Returns the text message in the given locale and the defaut timezone.
+     * @param loc the {@link Locale}
+     * @return the text message.
+     * @throws MissingEntryException if the message is not available
+     */
+    public String getText(Locale loc) throws MissingEntryException
+    {
+        return getEntry(TEXT_ENTRY,loc,TimeZone.getDefault());
+    }
+
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/i18n/filter/Filter.java b/libcore/security/src/main/java/org/bouncycastle/i18n/filter/Filter.java
new file mode 100644
index 0000000..aee58cb
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/i18n/filter/Filter.java
@@ -0,0 +1,14 @@
+
+package org.bouncycastle.i18n.filter;
+
+public interface Filter
+{
+
+    /**
+     * Runs the filter on the input String and returns the filtered String
+     * @param input input String
+     * @return filtered String
+     */
+    public String doFilter(String input);
+
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/i18n/filter/HTMLFilter.java b/libcore/security/src/main/java/org/bouncycastle/i18n/filter/HTMLFilter.java
new file mode 100644
index 0000000..defc610
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/i18n/filter/HTMLFilter.java
@@ -0,0 +1,63 @@
+
+package org.bouncycastle.i18n.filter;
+
+/**
+ * HTML Filter
+ */
+public class HTMLFilter implements Filter 
+{
+
+    public String doFilter(String input) 
+    {
+        StringBuffer buf = new StringBuffer(input);
+        int i = 0;
+        while (i < buf.length()) 
+        {
+            char ch = buf.charAt(i);
+            switch (ch)
+            {
+            case '<':
+                buf.replace(i,i+1,"&#60");
+                break;
+            case '>':
+                buf.replace(i,i+1,"&#62");
+                break;
+            case '(':
+                buf.replace(i,i+1,"&#40");
+                break;
+            case ')':
+                buf.replace(i,i+1,"&#41");
+                break;
+            case '#':
+                buf.replace(i,i+1,"&#35");
+                break;
+            case '&':
+                buf.replace(i,i+1,"&#38");
+                break;
+            case '\"':
+                buf.replace(i,i+1,"&#34");
+                break;
+            case '\'':
+                buf.replace(i,i+1,"&#39");
+                break;
+            case '%':
+                buf.replace(i,i+1,"&#37");
+                break;
+            case ';':
+                buf.replace(i,i+1,"&#59");
+                break;
+            case '+':
+                buf.replace(i,i+1,"&#43");
+                break;
+            case '-':
+                buf.replace(i,i+1,"&#45");
+                break;
+            default:
+                i -= 3;
+            }
+            i += 4;
+        }
+        return buf.toString();
+    }
+
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/i18n/filter/SQLFilter.java b/libcore/security/src/main/java/org/bouncycastle/i18n/filter/SQLFilter.java
new file mode 100644
index 0000000..ed3e488
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/i18n/filter/SQLFilter.java
@@ -0,0 +1,64 @@
+
+package org.bouncycastle.i18n.filter;
+
+/**
+ * Filter for strings to store in a SQL table.
+ * 
+ * escapes ' " = - / \ ; \r \n
+ */
+public class SQLFilter implements Filter
+{
+
+    public String doFilter(String input) 
+    {
+        StringBuffer buf = new StringBuffer(input);
+        int i = 0;
+        while (i < buf.length()) 
+        {
+            char ch = buf.charAt(i);
+            switch (ch) 
+            {
+            case '\'':
+                buf.replace(i,i+1,"\\\'");
+                i += 1;
+                break;
+            case '\"':
+                buf.replace(i,i+1,"\\\"");
+                i += 1;
+                break;
+            case '=':
+                buf.replace(i,i+1,"\\=");
+                i += 1;
+                break;
+            case '-':
+                buf.replace(i,i+1,"\\-");
+                i += 1;
+                break;
+            case '/':
+                buf.replace(i,i+1,"\\/");
+                i += 1;
+                break;
+            case '\\':
+                buf.replace(i,i+1,"\\\\");
+                i += 1;
+                break;
+            case ';':
+                buf.replace(i,i+1,"\\;");
+                i += 1;
+                break;
+            case '\r':
+                buf.replace(i,i+1,"\\r");
+                i += 1;
+                break;
+            case '\n':
+                buf.replace(i,i+1,"\\n");
+                i += 1;
+                break;
+            default:
+            }
+            i++;
+        }
+        return buf.toString();
+    }
+
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/i18n/filter/UntrustedInput.java b/libcore/security/src/main/java/org/bouncycastle/i18n/filter/UntrustedInput.java
new file mode 100644
index 0000000..cc69ac4
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/i18n/filter/UntrustedInput.java
@@ -0,0 +1,44 @@
+
+package org.bouncycastle.i18n.filter;
+
+/**
+ * Wrapper class to mark untrusted input.
+ */
+public class UntrustedInput 
+{
+
+    protected Object input;
+
+    /**
+     * Construct a new UntrustedInput instance.
+     * @param input the untrusted input Object
+     */
+    public UntrustedInput(Object input) 
+    {
+        this.input = input;
+    }
+
+    /**
+     * Returns the untrusted input as Object.
+     * @return the <code>input</code> as Object
+     */
+    public Object getInput() 
+    {
+        return input;
+    }
+
+    /**
+     * Returns the untrusted input convertet to a String.
+     * @return the <code>input</code> as String
+     */
+    public String getString() 
+    {
+        return input.toString();
+    }
+    
+    public String toString()
+    {
+        return input.toString();
+    }
+
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java b/libcore/security/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java
new file mode 100644
index 0000000..eabb6d9
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java
@@ -0,0 +1,446 @@
+package org.bouncycastle.jce;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Hashtable;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.CertificationRequest;
+import org.bouncycastle.asn1.pkcs.CertificationRequestInfo;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x509.X509Name;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.util.Strings;
+
+/**
+ * A class for verifying and creating PKCS10 Certification requests. 
+ * <pre>
+ * CertificationRequest ::= SEQUENCE {
+ *   certificationRequestInfo  CertificationRequestInfo,
+ *   signatureAlgorithm        AlgorithmIdentifier{{ SignatureAlgorithms }},
+ *   signature                 BIT STRING
+ * }
+ *
+ * CertificationRequestInfo ::= SEQUENCE {
+ *   version             INTEGER { v1(0) } (v1,...),
+ *   subject             Name,
+ *   subjectPKInfo   SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
+ *   attributes          [0] Attributes{{ CRIAttributes }}
+ *  }
+ *
+ *  Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }}
+ *
+ *  Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE {
+ *    type    ATTRIBUTE.&id({IOSet}),
+ *    values  SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type})
+ *  }
+ * </pre>
+ */
+public class PKCS10CertificationRequest
+    extends CertificationRequest
+{
+    private static Hashtable            algorithms = new Hashtable();
+    private static Hashtable            keyAlgorithms = new Hashtable();
+    private static Hashtable            oids = new Hashtable();
+    private static Set                  noParams = new HashSet();
+
+    static
+    {
+        algorithms.put("MD2WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
+        algorithms.put("MD2WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
+        algorithms.put("MD5WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
+        algorithms.put("MD5WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
+        algorithms.put("RSAWITHMD5", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
+        algorithms.put("SHA1WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
+        algorithms.put("SHA1WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
+        algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+        algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+        algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+        algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+        algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+        algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+        algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+        algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+        algorithms.put("RSAWITHSHA1", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
+        algorithms.put("RIPEMD160WITHRSAENCRYPTION", new DERObjectIdentifier("1.3.36.3.3.1.2"));
+        algorithms.put("RIPEMD160WITHRSA", new DERObjectIdentifier("1.3.36.3.3.1.2"));
+        algorithms.put("SHA1WITHDSA", new DERObjectIdentifier("1.2.840.10040.4.3"));
+        algorithms.put("DSAWITHSHA1", new DERObjectIdentifier("1.2.840.10040.4.3"));
+        algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+        algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
+        algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+        algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+        algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+        algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+        algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+        algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
+        algorithms.put("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+        algorithms.put("GOST3410WITHGOST3411", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+        algorithms.put("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+        //algorithms.put("ECGOST3410WITHGOST3411", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+
+        //
+        // reverse mappings
+        //
+        oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA");
+        oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
+        oids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WITHRSA");
+        oids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WITHRSA");
+        oids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WITHRSA");
+        oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3411WITHGOST3410");
+        //oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "GOST3411WITHECGOST3410");
+        
+        oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA");
+        oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA");
+        oids.put(new DERObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA");
+        oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1WITHECDSA");
+        oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
+        oids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256WITHECDSA");
+        oids.put(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384WITHECDSA");
+        oids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512WITHECDSA");
+        oids.put(OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA");
+        oids.put(OIWObjectIdentifiers.dsaWithSHA1, "SHA1WITHDSA");
+        oids.put(NISTObjectIdentifiers.dsa_with_sha224, "SHA224WITHDSA");
+        oids.put(NISTObjectIdentifiers.dsa_with_sha256, "SHA256WITHDSA");
+        
+        //
+        // key types
+        //
+        keyAlgorithms.put(PKCSObjectIdentifiers.rsaEncryption, "RSA");
+        keyAlgorithms.put(X9ObjectIdentifiers.id_dsa, "DSA");
+        
+        //
+        // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field. 
+        // The parameters field SHALL be NULL for RSA based signature algorithms.
+        //
+        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
+        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
+        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);
+        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);
+        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);
+        noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);
+        noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
+        noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
+    }
+
+    private static ASN1Sequence toDERSequence(
+        byte[]  bytes)
+    {
+        try
+        {
+            ByteArrayInputStream    bIn = new ByteArrayInputStream(bytes);
+            ASN1InputStream         dIn = new ASN1InputStream(bIn);
+
+            return (ASN1Sequence)dIn.readObject();
+        }
+        catch (Exception e)
+        {
+            throw new IllegalArgumentException("badly encoded request");
+        }
+    }
+
+    /**
+     * construct a PKCS10 certification request from a DER encoded
+     * byte stream.
+     */
+    public PKCS10CertificationRequest(
+        byte[]  bytes)
+    {
+        super(toDERSequence(bytes));
+    }
+
+    public PKCS10CertificationRequest(
+        ASN1Sequence  sequence)
+    {
+        super(sequence);
+    }
+
+    /**
+     * create a PKCS10 certfication request using the BC provider.
+     */
+    public PKCS10CertificationRequest(
+        String              signatureAlgorithm,
+        X509Name            subject,
+        PublicKey           key,
+        ASN1Set             attributes,
+        PrivateKey          signingKey)
+        throws NoSuchAlgorithmException, NoSuchProviderException,
+                InvalidKeyException, SignatureException
+    {
+        this(signatureAlgorithm, subject, key, attributes, signingKey, "BC");
+    }
+
+    private static X509Name convertName(
+        X500Principal    name)
+    {
+        try
+        {
+            return new X509Principal(name.getEncoded());
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("can't convert name");
+        }
+    }
+    
+    /**
+     * create a PKCS10 certfication request using the BC provider.
+     */
+    public PKCS10CertificationRequest(
+        String              signatureAlgorithm,
+        X500Principal       subject,
+        PublicKey           key,
+        ASN1Set             attributes,
+        PrivateKey          signingKey)
+        throws NoSuchAlgorithmException, NoSuchProviderException,
+                InvalidKeyException, SignatureException
+    {
+        this(signatureAlgorithm, convertName(subject), key, attributes, signingKey, "BC");
+    }
+    
+    /**
+     * create a PKCS10 certfication request using the named provider.
+     */
+    public PKCS10CertificationRequest(
+        String              signatureAlgorithm,
+        X500Principal       subject,
+        PublicKey           key,
+        ASN1Set             attributes,
+        PrivateKey          signingKey,
+        String              provider)
+        throws NoSuchAlgorithmException, NoSuchProviderException,
+                InvalidKeyException, SignatureException
+    {
+        this(signatureAlgorithm, convertName(subject), key, attributes, signingKey, provider);
+    }
+    
+    /**
+     * create a PKCS10 certfication request using the named provider.
+     */
+    public PKCS10CertificationRequest(
+        String              signatureAlgorithm,
+        X509Name            subject,
+        PublicKey           key,
+        ASN1Set             attributes,
+        PrivateKey          signingKey,
+        String              provider)
+        throws NoSuchAlgorithmException, NoSuchProviderException,
+                InvalidKeyException, SignatureException
+    {
+        DERObjectIdentifier sigOID = (DERObjectIdentifier)algorithms.get(Strings.toUpperCase(signatureAlgorithm));
+
+        if (sigOID == null)
+        {
+            throw new IllegalArgumentException("Unknown signature type requested");
+        }
+
+        if (subject == null)
+        {
+            throw new IllegalArgumentException("subject must not be null");
+        }
+
+        if (key == null)
+        {
+            throw new IllegalArgumentException("public key must not be null");
+        }
+
+        if (noParams.contains(sigOID))
+        {
+            this.sigAlgId = new AlgorithmIdentifier(sigOID);
+        }
+        else
+        {
+            this.sigAlgId = new AlgorithmIdentifier(sigOID, null);
+        }
+
+        byte[]                  bytes = key.getEncoded();
+        ByteArrayInputStream    bIn = new ByteArrayInputStream(bytes);
+        ASN1InputStream         dIn = new ASN1InputStream(bIn);
+
+        try
+        {
+            this.reqInfo = new CertificationRequestInfo(subject, new SubjectPublicKeyInfo((ASN1Sequence)dIn.readObject()), attributes);
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("can't encode public key");
+        }
+
+        Signature sig = null;
+        
+        try
+        {
+            sig = Signature.getInstance(sigAlgId.getObjectId().getId(), provider);
+        }
+        catch (NoSuchAlgorithmException e)
+        {
+            sig = Signature.getInstance(signatureAlgorithm, provider);
+        }
+
+        sig.initSign(signingKey);
+
+        try
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DEROutputStream         dOut = new DEROutputStream(bOut);
+
+            dOut.writeObject(reqInfo);
+
+            sig.update(bOut.toByteArray());
+        }
+        catch (Exception e)
+        {
+            throw new SecurityException("exception encoding TBS cert request - " + e);
+        }
+
+        this.sigBits = new DERBitString(sig.sign());
+    }
+
+    /**
+     * return the public key associated with the certification request -
+     * the public key is created using the BC provider.
+     */
+    public PublicKey getPublicKey()
+        throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException
+    {
+        return getPublicKey("BC");
+    }
+
+    public PublicKey getPublicKey(
+        String  provider)
+        throws NoSuchAlgorithmException, NoSuchProviderException,
+                InvalidKeyException
+    {
+        SubjectPublicKeyInfo    subjectPKInfo = reqInfo.getSubjectPublicKeyInfo();
+        X509EncodedKeySpec      xspec = new X509EncodedKeySpec(new DERBitString(subjectPKInfo).getBytes());
+        AlgorithmIdentifier     keyAlg = subjectPKInfo.getAlgorithmId();
+        
+        try
+        {
+            try
+            {
+                return KeyFactory.getInstance(keyAlg.getObjectId().getId(), provider).generatePublic(xspec);
+            }
+            catch (NoSuchAlgorithmException e)
+            {
+                //
+                // try an alternate
+                //
+                if (keyAlgorithms.get(keyAlg.getObjectId()) != null)
+                {
+                    String  keyAlgorithm = (String)keyAlgorithms.get(keyAlg.getObjectId());
+                    
+                    return KeyFactory.getInstance(keyAlgorithm, provider).generatePublic(xspec);
+                }
+                
+                throw e;
+            }
+        }
+        catch (InvalidKeySpecException e)
+        {
+            throw new InvalidKeyException("error decoding public key");
+        }
+    }
+
+    /**
+     * verify the request using the BC provider.
+     */
+    public boolean verify()
+        throws NoSuchAlgorithmException, NoSuchProviderException,
+                InvalidKeyException, SignatureException
+    {
+        return verify("BC");
+    }
+
+    public boolean verify(
+        String provider)
+        throws NoSuchAlgorithmException, NoSuchProviderException,
+                InvalidKeyException, SignatureException
+    {
+        Signature   sig = null;
+
+        try
+        {
+            sig = Signature.getInstance(sigAlgId.getObjectId().getId(), provider);
+        }
+        catch (NoSuchAlgorithmException e)
+        {
+            //
+            // try an alternate
+            //
+            if (oids.get(sigAlgId.getObjectId()) != null)
+            {
+                String  signatureAlgorithm = (String)oids.get(sigAlgId.getObjectId());
+
+                sig = Signature.getInstance(signatureAlgorithm, provider);
+            }
+            else
+            {
+                throw e;
+            }
+        }
+
+        sig.initVerify(this.getPublicKey(provider));
+
+        try
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DEROutputStream         dOut = new DEROutputStream(bOut);
+
+            dOut.writeObject(reqInfo);
+
+            sig.update(bOut.toByteArray());
+        }
+        catch (Exception e)
+        {
+            throw new SecurityException("exception encoding TBS cert request - " + e);
+        }
+
+        return sig.verify(sigBits.getBytes());
+    }
+
+    /**
+     * return a DER encoded byte array representing this object
+     */
+    public byte[] getEncoded()
+    {
+        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+        DEROutputStream         dOut = new DEROutputStream(bOut);
+
+        try
+        {
+            dOut.writeObject(this);
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException(e.toString());
+        }
+
+        return bOut.toByteArray();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/PKCS7SignedData.java b/libcore/security/src/main/java/org/bouncycastle/jce/PKCS7SignedData.java
new file mode 100644
index 0000000..cd05b9f
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/PKCS7SignedData.java
@@ -0,0 +1,600 @@
+package org.bouncycastle.jce;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.bouncycastle.asn1.*;
+import org.bouncycastle.asn1.pkcs.ContentInfo;
+import org.bouncycastle.asn1.pkcs.IssuerAndSerialNumber;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.SignedData;
+import org.bouncycastle.asn1.pkcs.SignerInfo;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.CertificateList;
+import org.bouncycastle.asn1.x509.X509CertificateStructure;
+import org.bouncycastle.asn1.x509.X509Name;
+import org.bouncycastle.jce.provider.X509CRLObject;
+import org.bouncycastle.jce.provider.X509CertificateObject;
+
+/**
+ * Represents a PKCS#7 object - specifically the "Signed Data"
+ * type.
+ * <p>
+ * How to use it? To verify a signature, do:
+ * <pre>
+ * PKCS7SignedData pkcs7 = new PKCS7SignedData(der_bytes);        // Create it
+ * pkcs7.update(bytes, 0, bytes.length);                          // Update checksum
+ * boolean verified = pkcs7.verify();                             // Does it add up?
+ *
+ * To sign, do this:
+ * PKCS7SignedData pkcs7 = new PKCS7SignedData(privKey, certChain, "MD5");
+ * pkcs7.update(bytes, 0, bytes.length);                          // Update checksum
+ * pkcs7.sign();                                                  // Create digest
+ *
+ * bytes = pkcs7.getEncoded();                                    // Write it somewhere
+ * </pre>
+ * <p>
+ * This class is pretty close to obsolete, for a much better (and more complete)
+ * implementation of PKCS7 have a look at the org.bouncycastle.cms package.
+ * @deprecated this class really is obsolete - use the CMS package.
+ */
+public class PKCS7SignedData
+    implements PKCSObjectIdentifiers
+{
+    private int version, signerversion;
+    private Set digestalgos;
+    private Collection certs, crls;
+    private X509Certificate signCert;
+    private byte[] digest;
+    private String digestAlgorithm, digestEncryptionAlgorithm;
+    private Signature sig;
+    private transient PrivateKey privKey;
+
+    private final String ID_PKCS7_DATA = "1.2.840.113549.1.7.1";
+    private final String ID_PKCS7_SIGNED_DATA = "1.2.840.113549.1.7.2";
+    private final String ID_MD5 = "1.2.840.113549.2.5";
+    private final String ID_MD2 = "1.2.840.113549.2.2";
+    private final String ID_SHA1 = "1.3.14.3.2.26";
+    private final String ID_RSA = "1.2.840.113549.1.1.1";
+    private final String ID_DSA = "1.2.840.10040.4.1";
+
+    /**
+     * Read an existing PKCS#7 object from a DER encoded byte array using
+     * the BC provider.
+     */
+    public PKCS7SignedData(
+        byte[]  in)
+        throws SecurityException, CRLException, InvalidKeyException,
+        NoSuchProviderException, NoSuchAlgorithmException
+    {
+        this(in, "BC");
+    }
+
+    /**
+     * Read an existing PKCS#7 object from a DER encoded byte array 
+     */
+    public PKCS7SignedData(
+        byte[]  in,
+        String  provider)
+        throws SecurityException, CRLException, InvalidKeyException,
+        NoSuchProviderException, NoSuchAlgorithmException
+    {
+        ASN1InputStream din = new ASN1InputStream(new ByteArrayInputStream(in));
+
+        //
+        // Basic checks to make sure it's a PKCS#7 SignedData Object
+        //
+        DERObject pkcs;
+
+        try
+        {
+            pkcs = din.readObject();
+        }
+        catch (IOException e)
+        {
+            throw new SecurityException("can't decode PKCS7SignedData object");
+        }
+
+        if (!(pkcs instanceof ASN1Sequence))
+        {
+            throw new SecurityException("Not a valid PKCS#7 object - not a sequence");
+        }
+
+        ContentInfo content = ContentInfo.getInstance(pkcs);
+
+        if (!content.getContentType().equals(signedData))
+        {
+            throw new SecurityException("Not a valid PKCS#7 signed-data object - wrong header " + content.getContentType().getId());
+        }
+
+
+        SignedData  data = SignedData.getInstance(content.getContent());
+
+        certs = new ArrayList();
+
+        if (data.getCertificates() != null)
+        {
+            Enumeration ec = ASN1Set.getInstance(data.getCertificates()).getObjects();
+
+            while (ec.hasMoreElements())
+            {
+                certs.add(new X509CertificateObject(X509CertificateStructure.getInstance(ec.nextElement())));
+            }
+        }
+
+        crls = new ArrayList();
+
+        if (data.getCRLs() != null)
+        {
+            Enumeration ec = ASN1Set.getInstance(data.getCRLs()).getObjects();
+            while (ec.hasMoreElements())
+            {
+                crls.add(new X509CRLObject(CertificateList.getInstance(ec.nextElement())));
+            }
+        }
+
+        version = data.getVersion().getValue().intValue();
+
+        //
+        // Get the digest algorithm
+        //
+        digestalgos = new HashSet();
+        Enumeration e = data.getDigestAlgorithms().getObjects();
+
+        while (e.hasMoreElements())
+        {
+            ASN1Sequence s = (ASN1Sequence)e.nextElement();
+            DERObjectIdentifier o = (DERObjectIdentifier)s.getObjectAt(0);
+            digestalgos.add(o.getId());
+        }
+
+        //
+        // Get the SignerInfo
+        //
+        ASN1Set signerinfos = data.getSignerInfos();
+        if (signerinfos.size() != 1)
+        {
+            throw new SecurityException("This PKCS#7 object has multiple SignerInfos - only one is supported at this time");
+        }
+
+        SignerInfo signerInfo = SignerInfo.getInstance(signerinfos.getObjectAt(0));
+
+        signerversion = signerInfo.getVersion().getValue().intValue();
+
+        IssuerAndSerialNumber isAnds = signerInfo.getIssuerAndSerialNumber();
+
+        //
+        // Get the signing certificate
+        //
+        BigInteger      serialNumber = isAnds.getCertificateSerialNumber().getValue();
+        X509Principal   issuer = new X509Principal(isAnds.getName());
+
+        for (Iterator i = certs.iterator();i.hasNext();)
+        {
+            X509Certificate cert = (X509Certificate)i.next();
+            if (serialNumber.equals(cert.getSerialNumber())
+                    && issuer.equals(cert.getIssuerDN()))
+            {
+                signCert = cert;
+                break;
+            }
+        }
+
+        if (signCert == null)
+        {
+            throw new SecurityException("Can't find signing certificate with serial "+serialNumber.toString(16)); 
+        }
+
+        digestAlgorithm = signerInfo.getDigestAlgorithm().getObjectId().getId();
+
+        digest = signerInfo.getEncryptedDigest().getOctets();
+        digestEncryptionAlgorithm = signerInfo.getDigestEncryptionAlgorithm().getObjectId().getId();
+
+        sig = Signature.getInstance(getDigestAlgorithm(), provider);
+
+        sig.initVerify(signCert.getPublicKey());
+    }
+
+    /**
+     * Create a new PKCS#7 object from the specified key using the BC provider.
+     *
+     * @param privKey the private key to be used for signing.
+     * @param certChain the certificate chain associated with the private key.
+     * @param hashAlgorithm the hashing algorithm used to compute the message digest. Must be "MD5", "MD2", "SHA1" or "SHA"
+     */
+    public PKCS7SignedData(
+        PrivateKey      privKey,
+        Certificate[]   certChain,
+        String          hashAlgorithm)
+        throws SecurityException, InvalidKeyException,
+        NoSuchProviderException, NoSuchAlgorithmException
+    {
+        this(privKey, certChain, hashAlgorithm, "BC");
+    }
+
+    /**
+     * Create a new PKCS#7 object from the specified key.
+     *
+     * @param privKey the private key to be used for signing.
+     * @param certChain the certificate chain associated with the private key.
+     * @param hashAlgorithm the hashing algorithm used to compute the message digest. Must be "MD5", "MD2", "SHA1" or "SHA"
+     * @param provider the provider to use.
+     */
+    public PKCS7SignedData(
+        PrivateKey      privKey,
+        Certificate[]   certChain,
+        String          hashAlgorithm,
+        String          provider)
+        throws SecurityException, InvalidKeyException,
+        NoSuchProviderException, NoSuchAlgorithmException
+    {
+        this(privKey, certChain, null, hashAlgorithm, provider);
+    }
+
+    /**
+     * Create a new PKCS#7 object from the specified key.
+     *
+     * @param privKey the private key to be used for signing.
+     * @param certChain the certificate chain associated with the private key.
+     * @param crlList the crl list associated with the private key.
+     * @param hashAlgorithm the hashing algorithm used to compute the message digest. Must be "MD5", "MD2", "SHA1" or "SHA"
+     * @param provider the provider to use.
+     */
+    public PKCS7SignedData(
+        PrivateKey      privKey,
+        Certificate[]   certChain,
+        CRL[]           crlList,
+        String          hashAlgorithm,
+        String          provider)
+        throws SecurityException, InvalidKeyException,
+        NoSuchProviderException, NoSuchAlgorithmException
+    {
+        this.privKey = privKey;
+
+        if (hashAlgorithm.equals("MD5"))
+        {
+            digestAlgorithm = ID_MD5;
+        }
+        else if (hashAlgorithm.equals("MD2"))
+        {
+            digestAlgorithm = ID_MD2;
+        }
+        else if (hashAlgorithm.equals("SHA"))
+        {
+            digestAlgorithm = ID_SHA1;
+        }
+        else if (hashAlgorithm.equals("SHA1"))
+        {
+            digestAlgorithm = ID_SHA1;
+        }
+        else
+        {
+            throw new NoSuchAlgorithmException("Unknown Hash Algorithm "+hashAlgorithm);
+        }
+
+        version = signerversion = 1;
+        certs = new ArrayList();
+        crls = new ArrayList();
+        digestalgos = new HashSet();
+        digestalgos.add(digestAlgorithm);
+
+        //
+        // Copy in the certificates and crls used to sign the private key.
+        //
+        signCert = (X509Certificate)certChain[0];
+        for (int i = 0;i < certChain.length;i++)
+        {
+            certs.add(certChain[i]);
+        }
+
+        if (crlList != null)
+        {
+            for (int i = 0;i < crlList.length;i++)
+            {
+                crls.add(crlList[i]);
+            }
+        }
+
+        //
+        // Now we have private key, find out what the digestEncryptionAlgorithm is.
+        //
+        digestEncryptionAlgorithm = privKey.getAlgorithm();
+        if (digestEncryptionAlgorithm.equals("RSA"))
+        {
+            digestEncryptionAlgorithm = ID_RSA;
+        }
+        else if (digestEncryptionAlgorithm.equals("DSA"))
+        {
+            digestEncryptionAlgorithm = ID_DSA;
+        }
+        else
+        {
+            throw new NoSuchAlgorithmException("Unknown Key Algorithm "+digestEncryptionAlgorithm);
+        }
+
+        sig = Signature.getInstance(getDigestAlgorithm(), provider);
+
+        sig.initSign(privKey);
+    }
+
+    /**
+     * Get the algorithm used to calculate the message digest
+     */
+    public String getDigestAlgorithm()
+    {
+        String da = digestAlgorithm;
+        String dea = digestEncryptionAlgorithm;
+
+        if (digestAlgorithm.equals(ID_MD5))
+        {
+            da = "MD5";
+        }
+        else if (digestAlgorithm.equals(ID_MD2))
+        {
+            da = "MD2";
+        }
+        else if (digestAlgorithm.equals(ID_SHA1))
+        {
+            da = "SHA1";
+        }
+
+        if (digestEncryptionAlgorithm.equals(ID_RSA))
+        {
+            dea = "RSA";
+        }
+        else if (digestEncryptionAlgorithm.equals(ID_DSA))
+        {
+            dea = "DSA";
+        }
+
+        return da + "with" + dea;
+    }
+
+    /**
+     * Resets the PKCS7SignedData object to it's initial state, ready
+     * to sign or verify a new buffer.
+     */
+    public void reset()
+    {
+        try
+        {
+            if (privKey==null)
+            {
+                sig.initVerify(signCert.getPublicKey());
+            }
+            else
+            {
+                sig.initSign(privKey);
+            }
+        }
+        catch (Exception e)
+        {
+            throw new RuntimeException(e.toString());
+        }
+    }
+
+    /**
+     * Get the X.509 certificates associated with this PKCS#7 object
+     */
+    public Certificate[] getCertificates()
+    {
+        return (X509Certificate[])certs.toArray(new X509Certificate[certs.size()]);
+    }
+
+    /**
+     * Get the X.509 certificate revocation lists associated with this PKCS#7 object
+     */
+    public Collection getCRLs()
+    {
+        return crls;
+    }
+    
+    /**
+     * Get the X.509 certificate actually used to sign the digest.
+     */
+    public X509Certificate getSigningCertificate()
+    {
+        return signCert;
+    }
+
+    /**
+     * Get the version of the PKCS#7 object. Always 1
+     */
+    public int getVersion()
+    {
+        return version;
+    }
+
+    /**
+     * Get the version of the PKCS#7 "SignerInfo" object. Always 1
+     */
+    public int getSigningInfoVersion()
+    {
+        return signerversion;
+    }
+
+    /**
+     * Update the digest with the specified byte. This method is used both for signing and verifying
+     */
+    public void update(byte buf)
+        throws SignatureException
+    {
+        sig.update(buf);
+    }
+
+    /**
+     * Update the digest with the specified bytes. This method is used both for signing and verifying
+     */
+    public void update(byte[] buf, int off, int len)
+        throws SignatureException
+    {
+        sig.update(buf, off, len);
+    }
+
+    /**
+     * Verify the digest
+     */
+    public boolean verify()
+        throws SignatureException
+    {
+        return sig.verify(digest);
+    }
+
+    /**
+     * Get the "issuer" from the TBSCertificate bytes that are passed in
+     */
+    private DERObject getIssuer(byte[] enc)
+    {
+        try
+        {
+            ASN1InputStream in = new ASN1InputStream(new ByteArrayInputStream(enc));
+            ASN1Sequence seq = (ASN1Sequence)in.readObject();
+            return (DERObject)seq.getObjectAt(seq.getObjectAt(0) instanceof DERTaggedObject ? 3 : 2);
+        }
+        catch (IOException e)
+        {
+            throw new Error("IOException reading from ByteArray: "+e);
+        }
+    }
+
+    /**
+     * return the bytes for the PKCS7SignedData object.
+     */
+    public byte[] getEncoded()
+    {
+        try
+        {
+        
+            digest = sig.sign();
+
+            // Create the set of Hash algorithms. I've assumed this is the
+            // set of all hash agorithms used to created the digest in the
+            // "signerInfo" structure. I may be wrong.
+            //
+            ASN1EncodableVector v = new ASN1EncodableVector();
+            for (Iterator i = digestalgos.iterator(); i.hasNext();)
+            {
+                AlgorithmIdentifier a = new AlgorithmIdentifier(
+                            new DERObjectIdentifier((String)i.next()),
+                            null);
+                
+                v.add(a);
+            }
+
+            DERSet algos = new DERSet(v);
+
+            // Create the contentInfo. Empty, I didn't implement this bit
+            //
+            DERSequence contentinfo = new DERSequence(
+                                        new DERObjectIdentifier(ID_PKCS7_DATA));
+
+            // Get all the certificates
+            //
+            v = new ASN1EncodableVector();
+            for (Iterator i = certs.iterator();i.hasNext();)
+            {
+                ASN1InputStream tempstream = new ASN1InputStream(new ByteArrayInputStream(((X509Certificate)i.next()).getEncoded()));
+                v.add(tempstream.readObject());
+            }
+
+            DERSet dercertificates = new DERSet(v);
+
+            // Create signerinfo structure.
+            //
+            ASN1EncodableVector signerinfo = new ASN1EncodableVector();
+
+            // Add the signerInfo version
+            //
+            signerinfo.add(new DERInteger(signerversion));
+
+            IssuerAndSerialNumber isAnds = new IssuerAndSerialNumber(
+                        new X509Name((ASN1Sequence)getIssuer(signCert.getTBSCertificate())),
+                        new DERInteger(signCert.getSerialNumber()));
+            signerinfo.add(isAnds);
+
+            // Add the digestAlgorithm
+            //
+            // BEGIN android-changed
+            signerinfo.add(new AlgorithmIdentifier(
+                                new DERObjectIdentifier(digestAlgorithm),
+                                DERNull.THE_ONE));
+
+            //
+            // Add the digestEncryptionAlgorithm
+            //
+            signerinfo.add(new AlgorithmIdentifier(
+                                new DERObjectIdentifier(digestEncryptionAlgorithm),
+                                DERNull.THE_ONE));
+            // END android-changed
+
+            //
+            // Add the digest
+            //
+            signerinfo.add(new DEROctetString(digest));
+
+
+            //
+            // Finally build the body out of all the components above
+            //
+            ASN1EncodableVector body = new ASN1EncodableVector();
+            body.add(new DERInteger(version));
+            body.add(algos);
+            body.add(contentinfo);
+            body.add(new DERTaggedObject(false, 0, dercertificates));
+
+            if (crls.size()>0)
+            {
+                v = new ASN1EncodableVector();
+                for (Iterator i = crls.iterator();i.hasNext();)
+                {
+                    ASN1InputStream t = new ASN1InputStream(new ByteArrayInputStream(((X509CRL)i.next()).getEncoded()));
+                    v.add(t.readObject());
+                }
+                DERSet dercrls = new DERSet(v);
+                body.add(new DERTaggedObject(false, 1, dercrls));
+            }
+
+            // Only allow one signerInfo
+            //
+            body.add(new DERSet(new DERSequence(signerinfo)));
+
+            // Now we have the body, wrap it in it's PKCS7Signed shell
+            // and return it
+            //
+            ASN1EncodableVector whole = new ASN1EncodableVector();
+            whole.add(new DERObjectIdentifier(ID_PKCS7_SIGNED_DATA));
+            whole.add(new DERTaggedObject(0, new DERSequence(body)));
+
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+
+            DEROutputStream dout = new DEROutputStream(bOut);
+            dout.writeObject(new DERSequence(whole));
+            dout.close();
+
+            return bOut.toByteArray();
+        }
+        catch (Exception e)
+        {
+            throw new RuntimeException(e.toString());
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/PrincipalUtil.java b/libcore/security/src/main/java/org/bouncycastle/jce/PrincipalUtil.java
new file mode 100644
index 0000000..92a444c
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/PrincipalUtil.java
@@ -0,0 +1,86 @@
+package org.bouncycastle.jce;
+
+import java.io.*;
+import java.security.cert.*;
+
+import org.bouncycastle.asn1.*;
+import org.bouncycastle.asn1.x509.*;
+
+/**
+ * a utility class that will extract X509Principal objects from X.509 certificates.
+ * <p>
+ * Use this in preference to trying to recreate a principal from a String, not all
+ * DNs are what they should be, so it's best to leave them encoded where they
+ * can be.
+ */
+public class PrincipalUtil
+{
+    /**
+     * return the issuer of the given cert as an X509PrincipalObject.
+     */
+    public static X509Principal getIssuerX509Principal(
+        X509Certificate cert)
+        throws CertificateEncodingException
+    {
+        try
+        {
+            ByteArrayInputStream    bIn = new ByteArrayInputStream(
+                cert.getTBSCertificate());
+            ASN1InputStream         aIn = new ASN1InputStream(bIn);
+            TBSCertificateStructure tbsCert = new TBSCertificateStructure(
+                                            (ASN1Sequence)aIn.readObject());
+
+            return new X509Principal(tbsCert.getIssuer());
+        }
+        catch (IOException e)
+        {
+            throw new CertificateEncodingException(e.toString());
+        }
+    }
+
+    /**
+     * return the subject of the given cert as an X509PrincipalObject.
+     */
+    public static X509Principal getSubjectX509Principal(
+        X509Certificate cert)
+        throws CertificateEncodingException
+    {
+        try
+        {
+            ByteArrayInputStream    bIn = new ByteArrayInputStream(
+                cert.getTBSCertificate());
+            ASN1InputStream         aIn = new ASN1InputStream(bIn);
+            TBSCertificateStructure tbsCert = new TBSCertificateStructure(
+                                            (ASN1Sequence)aIn.readObject());
+
+            return new X509Principal(tbsCert.getSubject());
+        }
+        catch (IOException e)
+        {
+            throw new CertificateEncodingException(e.toString());
+        }
+    }
+    
+    /**
+     * return the issuer of the given CRL as an X509PrincipalObject.
+     */
+    public static X509Principal getIssuerX509Principal(
+        X509CRL crl)
+        throws CRLException
+    {
+        try
+        {
+            ByteArrayInputStream    bIn = new ByteArrayInputStream(
+                crl.getTBSCertList());
+            ASN1InputStream         aIn = new ASN1InputStream(bIn);
+            TBSCertList tbsCertList = new TBSCertList(
+                                            (ASN1Sequence)aIn.readObject());
+
+            return new X509Principal(tbsCertList.getIssuer());
+        }
+        catch (IOException e)
+        {
+            throw new CRLException(e.toString());
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/X509KeyUsage.java b/libcore/security/src/main/java/org/bouncycastle/jce/X509KeyUsage.java
new file mode 100644
index 0000000..2024b65
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/X509KeyUsage.java
@@ -0,0 +1,57 @@
+package org.bouncycastle.jce;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.x509.KeyUsage;
+
+/**
+ * A holding class for constructing an X509 Key Usage extension.
+ *
+ * <pre>
+ *    id-ce-keyUsage OBJECT IDENTIFIER ::=  { id-ce 15 }
+ *
+ *    KeyUsage ::= BIT STRING {
+ *         digitalSignature        (0),
+ *         nonRepudiation          (1),
+ *         keyEncipherment         (2),
+ *         dataEncipherment        (3),
+ *         keyAgreement            (4),
+ *         keyCertSign             (5),
+ *         cRLSign                 (6),
+ *         encipherOnly            (7),
+ *         decipherOnly            (8) }
+ * </pre>
+ */
+public class X509KeyUsage
+    extends ASN1Encodable
+{
+    public static final int        digitalSignature = 1 << 7; 
+    public static final int        nonRepudiation   = 1 << 6;
+    public static final int        keyEncipherment  = 1 << 5;
+    public static final int        dataEncipherment = 1 << 4;
+    public static final int        keyAgreement     = 1 << 3;
+    public static final int        keyCertSign      = 1 << 2;
+    public static final int        cRLSign          = 1 << 1;
+    public static final int        encipherOnly     = 1 << 0;
+    public static final int        decipherOnly     = 1 << 15;
+
+    private int usage = 0;
+
+    /**
+     * Basic constructor.
+     * 
+     * @param usage - the bitwise OR of the Key Usage flags giving the
+     * allowed uses for the key.
+     * e.g. (X509KeyUsage.keyEncipherment | X509KeyUsage.dataEncipherment)
+     */
+    public X509KeyUsage(
+        int usage)
+    {
+        this.usage = usage;
+    }
+
+    public DERObject toASN1Object()
+    {
+        return new KeyUsage(usage);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/X509Principal.java b/libcore/security/src/main/java/org/bouncycastle/jce/X509Principal.java
new file mode 100644
index 0000000..7051073
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/X509Principal.java
@@ -0,0 +1,151 @@
+package org.bouncycastle.jce;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.Principal;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.asn1.x509.X509Name;
+
+public class X509Principal
+    extends X509Name
+    implements Principal
+{
+    private static ASN1Sequence readSequence(
+        ASN1InputStream aIn)
+        throws IOException
+    {
+        try
+        {
+            return ASN1Sequence.getInstance(aIn.readObject());
+        }
+        catch (IllegalArgumentException e)
+        {
+            throw new IOException("not an ASN.1 Sequence: " + e);
+        }
+    }
+
+    /**
+     * Constructor from an encoded byte array.
+     */
+    public X509Principal(
+        byte[]  bytes)
+        throws IOException
+    {
+        super(readSequence(new ASN1InputStream(bytes)));
+    }
+
+    /**
+     * Constructor from an X509Name object.
+     */
+    public X509Principal(
+        X509Name  name)
+    {
+        super((ASN1Sequence)name.getDERObject());
+    }
+
+    /**
+     * constructor from a table of attributes.
+     * <p>
+     * it's is assumed the table contains OID/String pairs.
+     */
+    public X509Principal(
+        Hashtable  attributes)
+    {
+        super(attributes);
+    }
+
+    /**
+     * constructor from a table of attributes and a vector giving the
+     * specific ordering required for encoding or conversion to a string.
+     * <p>
+     * it's is assumed the table contains OID/String pairs.
+     */
+    public X509Principal(
+        Vector      ordering,
+        Hashtable   attributes)
+    {
+        super(ordering, attributes);
+    }
+
+    /**
+     * constructor from a vector of attribute values and a vector of OIDs.
+     */
+    public X509Principal(
+        Vector      oids,
+        Vector      values)
+    {
+        super(oids, values);
+    }
+
+    /**
+     * takes an X509 dir name as a string of the format "C=AU,ST=Victoria", or
+     * some such, converting it into an ordered set of name attributes.
+     */
+    public X509Principal(
+        String  dirName)
+    {
+        super(dirName);
+    }
+
+    /**
+     * Takes an X509 dir name as a string of the format "C=AU,ST=Victoria", or
+     * some such, converting it into an ordered set of name attributes. If reverse
+     * is false the dir name will be encoded in the order of the (name, value) pairs 
+     * presented, otherwise the encoding will start with the last (name, value) pair
+     * and work back.
+     */
+    public X509Principal(
+        boolean reverse,
+        String  dirName)
+    {
+        super(reverse, dirName);
+    }
+
+    /**
+     * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+     * some such, converting it into an ordered set of name attributes. lookUp 
+     * should provide a table of lookups, indexed by lowercase only strings and
+     * yielding a DERObjectIdentifier, other than that OID. and numeric oids
+     * will be processed automatically.
+     * <p>
+     * If reverse is true, create the encoded version of the sequence starting
+     * from the last element in the string.
+     */
+    public X509Principal(
+        boolean     reverse,
+        Hashtable   lookUp,
+        String      dirName)
+    {
+        super(reverse, lookUp, dirName);
+    }
+
+    public String getName()
+    {
+        return this.toString();
+    }
+
+    /**
+     * return a DER encoded byte array representing this object
+     */
+    public byte[] getEncoded()
+    {
+        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+        DEROutputStream         dOut = new DEROutputStream(bOut);
+
+        try
+        {
+            dOut.writeObject(this);
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException(e.toString());
+        }
+
+        return bOut.toByteArray();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/X509V1CertificateGenerator.java b/libcore/security/src/main/java/org/bouncycastle/jce/X509V1CertificateGenerator.java
new file mode 100644
index 0000000..4bd4c77
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/X509V1CertificateGenerator.java
@@ -0,0 +1,265 @@
+package org.bouncycastle.jce;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Hashtable;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x509.TBSCertificateStructure;
+import org.bouncycastle.asn1.x509.Time;
+import org.bouncycastle.asn1.x509.V1TBSCertificateGenerator;
+import org.bouncycastle.asn1.x509.X509CertificateStructure;
+import org.bouncycastle.asn1.x509.X509Name;
+import org.bouncycastle.jce.provider.X509CertificateObject;
+import org.bouncycastle.util.Strings;
+
+/**
+ * class to produce an X.509 Version 1 certificate.
+ * 
+ * @deprecated use the equivalent class in org.bouncycastle.x509
+ */
+public class X509V1CertificateGenerator
+{
+    private V1TBSCertificateGenerator   tbsGen;
+    private DERObjectIdentifier         sigOID;
+    private AlgorithmIdentifier         sigAlgId;
+    private String                      signatureAlgorithm;
+
+    private static Hashtable            algorithms = new Hashtable();
+
+    static
+    {
+        algorithms.put("MD2WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
+        algorithms.put("MD2WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
+        algorithms.put("MD5WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
+        algorithms.put("MD5WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
+        algorithms.put("SHA1WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
+        algorithms.put("SHA1WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
+        algorithms.put("RIPEMD160WITHRSAENCRYPTION", new DERObjectIdentifier("1.3.36.3.3.1.2"));
+        algorithms.put("RIPEMD160WITHRSA", new DERObjectIdentifier("1.3.36.3.3.1.2"));
+        algorithms.put("SHA1WITHDSA", new DERObjectIdentifier("1.2.840.10040.4.3"));
+        algorithms.put("DSAWITHSHA1", new DERObjectIdentifier("1.2.840.10040.4.3"));
+        algorithms.put("SHA1WITHECDSA", new DERObjectIdentifier("1.2.840.10045.4.1"));
+        algorithms.put("ECDSAWITHSHA1", new DERObjectIdentifier("1.2.840.10045.4.1"));
+    }
+
+    public X509V1CertificateGenerator()
+    {
+        tbsGen = new V1TBSCertificateGenerator();
+    }
+
+    /**
+     * reset the generator
+     */
+    public void reset()
+    {
+        tbsGen = new V1TBSCertificateGenerator();
+    }
+
+    /**
+     * set the serial number for the certificate.
+     */
+    public void setSerialNumber(
+        BigInteger      serialNumber)
+    {
+        tbsGen.setSerialNumber(new DERInteger(serialNumber));
+    }
+
+    /**
+     * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+     * certificate.
+     */
+    public void setIssuerDN(
+        X509Name   issuer)
+    {
+        tbsGen.setIssuer(issuer);
+    }
+
+    public void setNotBefore(
+        Date    date)
+    {
+        tbsGen.setStartDate(new Time(date));
+    }
+
+    public void setNotAfter(
+        Date    date)
+    {
+        tbsGen.setEndDate(new Time(date));
+    }
+
+    /**
+     * Set the subject distinguished name. The subject describes the entity associated with the public key.
+     */
+    public void setSubjectDN(
+        X509Name   subject)
+    {
+        tbsGen.setSubject(subject);
+    }
+
+    public void setPublicKey(
+        PublicKey       key)
+    {
+        try
+        {
+            tbsGen.setSubjectPublicKeyInfo(new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream(
+                                new ByteArrayInputStream(key.getEncoded())).readObject()));
+        }
+        catch (Exception e)
+        {
+            throw new IllegalArgumentException("unable to process key - " + e.toString());
+        }
+    }
+
+    public void setSignatureAlgorithm(
+        String  signatureAlgorithm)
+    {
+        this.signatureAlgorithm = signatureAlgorithm;
+
+        sigOID = (DERObjectIdentifier)algorithms.get(Strings.toUpperCase(signatureAlgorithm));
+
+        if (sigOID == null)
+        {
+            throw new IllegalArgumentException("Unknown signature type requested");
+        }
+
+        // BEGIN android-changed
+        sigAlgId = new AlgorithmIdentifier(this.sigOID, DERNull.THE_ONE);
+        // END android-changed
+
+        tbsGen.setSignature(sigAlgId);
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject
+     * using the default provider "BC".
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key)
+        throws SecurityException, SignatureException, InvalidKeyException
+    {
+        try
+        {
+            return generateX509Certificate(key, "BC", null);
+        }
+        catch (NoSuchProviderException e)
+        {
+            throw new SecurityException("BC provider not installed!");
+        }
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject
+     * using the default provider "BC" and the passed in source of randomness
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key,
+        SecureRandom    random)
+        throws SecurityException, SignatureException, InvalidKeyException
+    {
+        try
+        {
+            return generateX509Certificate(key, "BC", random);
+        }
+        catch (NoSuchProviderException e)
+        {
+            throw new SecurityException("BC provider not installed!");
+        }
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject,
+     * using the passed in provider for the signing, and the passed in source
+     * of randomness (if required).
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key,
+        String          provider)
+        throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+    {
+        return generateX509Certificate(key, provider, null);
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject,
+     * using the passed in provider for the signing, and the passed in source
+     * of randomness (if required).
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key,
+        String          provider,
+        SecureRandom    random)
+        throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+    {
+        Signature sig = null;
+
+        try
+        {
+            sig = Signature.getInstance(sigOID.getId(), provider);
+        }
+        catch (NoSuchAlgorithmException ex)
+        {
+            try
+            {
+                sig = Signature.getInstance(signatureAlgorithm, provider);
+            }
+            catch (NoSuchAlgorithmException e)
+            {
+                throw new SecurityException("exception creating signature: " + e.toString());
+            }
+        }
+
+        if (random != null)
+        {
+            sig.initSign(key, random);
+        }
+        else
+        {
+            sig.initSign(key);
+        }
+
+        TBSCertificateStructure tbsCert = tbsGen.generateTBSCertificate();
+
+        try
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DEROutputStream         dOut = new DEROutputStream(bOut);
+
+            dOut.writeObject(tbsCert);
+
+            sig.update(bOut.toByteArray());
+        }
+        catch (Exception e)
+        {
+            throw new SecurityException("exception encoding TBS cert - " + e);
+        }
+
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(tbsCert);
+        v.add(sigAlgId);
+        v.add(new DERBitString(sig.sign()));
+
+        return new X509CertificateObject(new X509CertificateStructure(new DERSequence(v)));
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/X509V2CRLGenerator.java b/libcore/security/src/main/java/org/bouncycastle/jce/X509V2CRLGenerator.java
new file mode 100644
index 0000000..dea70e2
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/X509V2CRLGenerator.java
@@ -0,0 +1,331 @@
+package org.bouncycastle.jce;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRL;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Hashtable;
+import java.util.SimpleTimeZone;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERUTCTime;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.CertificateList;
+import org.bouncycastle.asn1.x509.TBSCertList;
+import org.bouncycastle.asn1.x509.V2TBSCertListGenerator;
+import org.bouncycastle.asn1.x509.X509Extension;
+import org.bouncycastle.asn1.x509.X509Extensions;
+import org.bouncycastle.asn1.x509.X509Name;
+import org.bouncycastle.jce.provider.X509CRLObject;
+import org.bouncycastle.util.Strings;
+
+/**
+ * class to produce an X.509 Version 2 CRL.
+ * <p>
+ * @deprecated use the equivalent class in org.bouncycastle.x509
+ */
+public class X509V2CRLGenerator
+{
+    private SimpleDateFormat            dateF = new SimpleDateFormat("yyMMddHHmmss");
+    private SimpleTimeZone              tz = new SimpleTimeZone(0, "Z");
+    private V2TBSCertListGenerator      tbsGen;
+    private DERObjectIdentifier         sigOID;
+    private AlgorithmIdentifier         sigAlgId;
+    private String                      signatureAlgorithm;
+    private Hashtable                   extensions = null;
+    private Vector                      extOrdering = null;
+
+    private static Hashtable            algorithms = new Hashtable();
+
+    static
+    {
+        algorithms.put("MD2WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
+        algorithms.put("MD2WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
+        algorithms.put("MD5WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
+        algorithms.put("MD5WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
+        algorithms.put("SHA1WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
+        algorithms.put("SHA1WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
+        algorithms.put("RIPEMD160WITHRSAENCRYPTION", new DERObjectIdentifier("1.3.36.3.3.1.2"));
+        algorithms.put("RIPEMD160WITHRSA", new DERObjectIdentifier("1.3.36.3.3.1.2"));
+        algorithms.put("SHA1WITHDSA", new DERObjectIdentifier("1.2.840.10040.4.3"));
+        algorithms.put("DSAWITHSHA1", new DERObjectIdentifier("1.2.840.10040.4.3"));
+        algorithms.put("SHA1WITHECDSA", new DERObjectIdentifier("1.2.840.10045.4.1"));
+        algorithms.put("ECDSAWITHSHA1", new DERObjectIdentifier("1.2.840.10045.4.1"));
+    }
+
+    public X509V2CRLGenerator()
+    {
+        dateF.setTimeZone(tz);
+
+        tbsGen = new V2TBSCertListGenerator();
+    }
+
+    /**
+     * reset the generator
+     */
+    public void reset()
+    {
+        tbsGen = new V2TBSCertListGenerator();
+    }
+
+
+    /**
+     * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+     * certificate.
+     */
+    public void setIssuerDN(
+        X509Name   issuer)
+    {
+        tbsGen.setIssuer(issuer);
+    }
+
+    public void setThisUpdate(
+        Date    date)
+    {
+        tbsGen.setThisUpdate(new DERUTCTime(dateF.format(date) + "Z"));
+    }
+
+    public void setNextUpdate(
+        Date    date)
+    {
+        tbsGen.setNextUpdate(new DERUTCTime(dateF.format(date) + "Z"));
+    }
+
+    /**
+     * Reason being as indicated by ReasonFlags, i.e. ReasonFlags.KEY_COMPROMISE
+     * or 0 if ReasonFlags are not to be used
+     **/
+    public void addCRLEntry(BigInteger userCertificate, Date revocationDate, int reason)
+    {
+        tbsGen.addCRLEntry(new DERInteger(userCertificate), new DERUTCTime(dateF.format(revocationDate) + "Z"), reason);
+    }
+
+    public void setSignatureAlgorithm(
+        String  signatureAlgorithm)
+    {
+        this.signatureAlgorithm = signatureAlgorithm;
+
+        sigOID = (DERObjectIdentifier)algorithms.get(Strings.toUpperCase(signatureAlgorithm));
+
+        if (sigOID == null)
+        {
+            throw new IllegalArgumentException("Unknown signature type requested");
+        }
+
+        sigAlgId = new AlgorithmIdentifier(this.sigOID, null);
+
+        tbsGen.setSignature(sigAlgId);
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag (tag 3)
+     */
+    public void addExtension(
+        String          OID,
+        boolean         critical,
+        DEREncodable    value)
+    {
+        this.addExtension(new DERObjectIdentifier(OID), critical, value);
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag (tag 0)
+     */
+    public void addExtension(
+        DERObjectIdentifier OID,
+        boolean             critical,
+        DEREncodable        value)
+    {
+        if (extensions == null)
+        {
+            extensions = new Hashtable();
+            extOrdering = new Vector();
+        }
+
+        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+        DEROutputStream         dOut = new DEROutputStream(bOut);
+
+        try
+        {
+            dOut.writeObject(value);
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("error encoding value: " + e);
+        }
+
+        this.addExtension(OID, critical, bOut.toByteArray());
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag (tag 0)
+     */
+    public void addExtension(
+        String          OID,
+        boolean         critical,
+        byte[]          value)
+    {
+        this.addExtension(new DERObjectIdentifier(OID), critical, value);
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag (tag 0)
+     */
+    public void addExtension(
+        DERObjectIdentifier OID,
+        boolean             critical,
+        byte[]              value)
+    {
+        if (extensions == null)
+        {
+            extensions = new Hashtable();
+            extOrdering = new Vector();
+        }
+
+        extensions.put(OID, new X509Extension(critical, new DEROctetString(value)));
+        extOrdering.addElement(OID);
+    }
+
+    /**
+     * generate an X509 CRL, based on the current issuer and subject
+     * using the default provider "BC".
+     */
+    public X509CRL generateX509CRL(
+        PrivateKey      key)
+        throws SecurityException, SignatureException, InvalidKeyException
+    {
+        try
+        {
+            return generateX509CRL(key, "BC", null);
+        }
+        catch (NoSuchProviderException e)
+        {
+            throw new SecurityException("BC provider not installed!");
+        }
+    }
+
+    /**
+     * generate an X509 CRL, based on the current issuer and subject
+     * using the default provider "BC" and an user defined SecureRandom object as
+     * source of randomness.
+     */
+    public X509CRL generateX509CRL(
+        PrivateKey      key,
+        SecureRandom    random)
+        throws SecurityException, SignatureException, InvalidKeyException
+    {
+        try
+        {
+            return generateX509CRL(key, "BC", random);
+        }
+        catch (NoSuchProviderException e)
+        {
+            throw new SecurityException("BC provider not installed!");
+        }
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject
+     * using the passed in provider for the signing.
+     */
+    public X509CRL generateX509CRL(
+        PrivateKey      key,
+        String          provider)
+        throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+    {
+        return generateX509CRL(key, provider, null);
+    }
+
+    /**
+     * generate an X509 CRL, based on the current issuer and subject,
+     * using the passed in provider for the signing.
+     */
+    public X509CRL generateX509CRL(
+        PrivateKey      key,
+        String          provider,
+        SecureRandom    random)
+        throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+    {
+        Signature sig = null;
+
+        try
+        {
+            sig = Signature.getInstance(sigOID.getId(), provider);
+        }
+        catch (NoSuchAlgorithmException ex)
+        {
+            try
+            {
+                sig = Signature.getInstance(signatureAlgorithm, provider);
+            }
+            catch (NoSuchAlgorithmException e)
+            {
+                throw new SecurityException("exception creating signature: " + e.toString());
+            }
+        }
+
+        if (random != null)
+        {
+            sig.initSign(key, random);
+        }
+        else
+        {
+            sig.initSign(key);
+        }
+
+        if (extensions != null)
+        {
+            tbsGen.setExtensions(new X509Extensions(extOrdering, extensions));
+        }
+
+        TBSCertList tbsCrl = tbsGen.generateTBSCertList();
+
+        try
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DEROutputStream         dOut = new DEROutputStream(bOut);
+
+            dOut.writeObject(tbsCrl);
+
+            sig.update(bOut.toByteArray());
+        }
+        catch (Exception e)
+        {
+            throw new SecurityException("exception encoding TBS cert - " + e);
+        }
+
+        // Construct the CRL
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(tbsCrl);
+        v.add(sigAlgId);
+        v.add(new DERBitString(sig.sign()));
+
+        try
+        {
+            return new X509CRLObject(new CertificateList(new DERSequence(v)));
+        }
+        catch (CRLException e)
+        {
+            throw new IllegalStateException("attempt to create malformed CRL: " + e.getMessage());
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/X509V3CertificateGenerator.java b/libcore/security/src/main/java/org/bouncycastle/jce/X509V3CertificateGenerator.java
new file mode 100644
index 0000000..aec0365
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/X509V3CertificateGenerator.java
@@ -0,0 +1,345 @@
+package org.bouncycastle.jce;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.*;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x509.TBSCertificateStructure;
+import org.bouncycastle.asn1.x509.Time;
+import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
+import org.bouncycastle.asn1.x509.X509CertificateStructure;
+import org.bouncycastle.asn1.x509.X509Extension;
+import org.bouncycastle.asn1.x509.X509Extensions;
+import org.bouncycastle.asn1.x509.X509Name;
+import org.bouncycastle.jce.provider.X509CertificateObject;
+import org.bouncycastle.util.Strings;
+
+/**
+ * class to produce an X.509 Version 3 certificate.
+ * @deprecated use the equivalent class in org.bouncycastle.x509
+ */
+public class X509V3CertificateGenerator
+{
+    private V3TBSCertificateGenerator   tbsGen;
+    private DERObjectIdentifier         sigOID;
+    private AlgorithmIdentifier         sigAlgId;
+    private String                      signatureAlgorithm;
+    private Hashtable                   extensions = null;
+    private Vector                      extOrdering = null;
+
+    private static Hashtable            algorithms = new Hashtable();
+
+    static
+    {
+        algorithms.put("MD2WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
+        algorithms.put("MD2WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
+        algorithms.put("MD5WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
+        algorithms.put("MD5WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
+        algorithms.put("SHA1WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
+        algorithms.put("SHA1WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
+        algorithms.put("RIPEMD160WITHRSAENCRYPTION", new DERObjectIdentifier("1.3.36.3.3.1.2"));
+        algorithms.put("RIPEMD160WITHRSA", new DERObjectIdentifier("1.3.36.3.3.1.2"));
+        algorithms.put("SHA1WITHDSA", new DERObjectIdentifier("1.2.840.10040.4.3"));
+        algorithms.put("DSAWITHSHA1", new DERObjectIdentifier("1.2.840.10040.4.3"));
+        algorithms.put("SHA1WITHECDSA", new DERObjectIdentifier("1.2.840.10045.4.1"));
+        algorithms.put("ECDSAWITHSHA1", new DERObjectIdentifier("1.2.840.10045.4.1"));
+    }
+
+    public X509V3CertificateGenerator()
+    {
+        tbsGen = new V3TBSCertificateGenerator();
+    }
+
+    /**
+     * reset the generator
+     */
+    public void reset()
+    {
+        tbsGen = new V3TBSCertificateGenerator();
+        extensions = null;
+        extOrdering = null;
+    }
+
+    /**
+     * set the serial number for the certificate.
+     */
+    public void setSerialNumber(
+        BigInteger      serialNumber)
+    {
+        tbsGen.setSerialNumber(new DERInteger(serialNumber));
+    }
+
+    /**
+     * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+     * certificate.
+     */
+    public void setIssuerDN(
+        X509Name   issuer)
+    {
+        tbsGen.setIssuer(issuer);
+    }
+
+    public void setNotBefore(
+        Date    date)
+    {
+        tbsGen.setStartDate(new Time(date));
+    }
+
+    public void setNotAfter(
+        Date    date)
+    {
+        tbsGen.setEndDate(new Time(date));
+    }
+
+    /**
+     * Set the subject distinguished name. The subject describes the entity associated with the public key.
+     */
+    public void setSubjectDN(
+        X509Name   subject)
+    {
+        tbsGen.setSubject(subject);
+    }
+
+    public void setPublicKey(
+        PublicKey       key)
+    {
+        try
+        {
+            tbsGen.setSubjectPublicKeyInfo(new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream(
+                                new ByteArrayInputStream(key.getEncoded())).readObject()));
+        }
+        catch (Exception e)
+        {
+            throw new IllegalArgumentException("unable to process key - " + e.toString());
+        }
+    }
+
+    public void setSignatureAlgorithm(
+        String  signatureAlgorithm)
+    {
+        this.signatureAlgorithm = signatureAlgorithm;
+
+        sigOID = (DERObjectIdentifier)algorithms.get(Strings.toUpperCase(signatureAlgorithm));
+
+        if (sigOID == null)
+        {
+            throw new IllegalArgumentException("Unknown signature type requested");
+        }
+
+        // BEGIN android-changed
+        sigAlgId = new AlgorithmIdentifier(this.sigOID, DERNull.THE_ONE);
+        // END android-changed
+
+        tbsGen.setSignature(sigAlgId);
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag (tag 3)
+     */
+    public void addExtension(
+        String          OID,
+        boolean         critical,
+        DEREncodable    value)
+    {
+        this.addExtension(new DERObjectIdentifier(OID), critical, value);
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag (tag 3)
+     */
+    public void addExtension(
+        DERObjectIdentifier OID,
+        boolean             critical,
+        DEREncodable        value)
+    {
+        if (extensions == null)
+        {
+            extensions = new Hashtable();
+            extOrdering = new Vector();
+        }
+
+        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+        DEROutputStream         dOut = new DEROutputStream(bOut);
+
+        try
+        {
+            dOut.writeObject(value);
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("error encoding value: " + e);
+        }
+
+        this.addExtension(OID, critical, bOut.toByteArray());
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag (tag 3)
+     * The value parameter becomes the contents of the octet string associated
+     * with the extension.
+     */
+    public void addExtension(
+        String          OID,
+        boolean         critical,
+        byte[]          value)
+    {
+        this.addExtension(new DERObjectIdentifier(OID), critical, value);
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag (tag 3)
+     */
+    public void addExtension(
+        DERObjectIdentifier OID,
+        boolean             critical,
+        byte[]              value)
+    {
+        if (extensions == null)
+        {
+            extensions = new Hashtable();
+            extOrdering = new Vector();
+        }
+
+        extensions.put(OID, new X509Extension(critical, new DEROctetString(value)));
+        extOrdering.addElement(OID);
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject
+     * using the default provider "BC".
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key)
+        throws SecurityException, SignatureException, InvalidKeyException
+    {
+        try
+        {
+            return generateX509Certificate(key, "BC", null);
+        }
+        catch (NoSuchProviderException e)
+        {
+            throw new SecurityException("BC provider not installed!");
+        }
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject
+     * using the default provider "BC", and the passed in source of randomness
+     * (if required).
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key,
+        SecureRandom    random)
+        throws SecurityException, SignatureException, InvalidKeyException
+    {
+        try
+        {
+            return generateX509Certificate(key, "BC", random);
+        }
+        catch (NoSuchProviderException e)
+        {
+            throw new SecurityException("BC provider not installed!");
+        }
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject,
+     * using the passed in provider for the signing.
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key,
+        String          provider)
+        throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+    {
+        return generateX509Certificate(key, provider, null);
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject,
+     * using the passed in provider for the signing and the supplied source
+     * of randomness, if required.
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key,
+        String          provider,
+        SecureRandom    random)
+        throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+    {
+        Signature sig = null;
+
+        if (sigOID == null)
+        {
+            throw new IllegalStateException("no signature algorithm specified");
+        }
+
+        try
+        {
+            sig = Signature.getInstance(sigOID.getId(), provider);
+        }
+        catch (NoSuchAlgorithmException ex)
+        {
+            try
+            {
+                sig = Signature.getInstance(signatureAlgorithm, provider);
+            }
+            catch (NoSuchAlgorithmException e)
+            {
+                throw new SecurityException("exception creating signature: " + e.toString());
+            }
+        }
+
+        if (random != null)
+        {
+            sig.initSign(key, random);
+        }
+        else
+        {
+            sig.initSign(key);
+        }
+
+        if (extensions != null)
+        {
+            tbsGen.setExtensions(new X509Extensions(extOrdering, extensions));
+        }
+
+        TBSCertificateStructure tbsCert = tbsGen.generateTBSCertificate();
+
+        try
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DEROutputStream         dOut = new DEROutputStream(bOut);
+
+            dOut.writeObject(tbsCert);
+
+            sig.update(bOut.toByteArray());
+        }
+        catch (Exception e)
+        {
+            throw new SecurityException("exception encoding TBS cert - " + e);
+        }
+
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(tbsCert);
+        v.add(sigAlgId);
+        v.add(new DERBitString(sig.sign()));
+
+        return new X509CertificateObject(new X509CertificateStructure(new DERSequence(v)));
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/interfaces/BCKeyStore.java b/libcore/security/src/main/java/org/bouncycastle/jce/interfaces/BCKeyStore.java
new file mode 100644
index 0000000..a36abbb
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/interfaces/BCKeyStore.java
@@ -0,0 +1,14 @@
+package org.bouncycastle.jce.interfaces;
+
+import java.security.SecureRandom;
+
+/**
+ * all BC provider keystores implement this interface.
+ */
+public interface BCKeyStore
+{
+    /**
+     * set the random source for the key store
+     */
+    public void setRandom(SecureRandom random);
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/interfaces/IESKey.java b/libcore/security/src/main/java/org/bouncycastle/jce/interfaces/IESKey.java
new file mode 100644
index 0000000..f1d7901
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/interfaces/IESKey.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.jce.interfaces;
+
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * key pair for use with an integrated encryptor
+ */
+public interface IESKey
+    extends Key
+{
+    /**
+     * return the intended recipient's/sender's public key.
+     */
+    public PublicKey getPublic();
+
+    /**
+     * return the local private key.
+     */
+    public PrivateKey getPrivate();
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/interfaces/PKCS12BagAttributeCarrier.java b/libcore/security/src/main/java/org/bouncycastle/jce/interfaces/PKCS12BagAttributeCarrier.java
new file mode 100644
index 0000000..c5dd664
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/interfaces/PKCS12BagAttributeCarrier.java
@@ -0,0 +1,21 @@
+package org.bouncycastle.jce.interfaces;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+/**
+ * allow us to set attributes on objects that can go into a PKCS12 store.
+ */
+public interface PKCS12BagAttributeCarrier
+{
+    public void setBagAttribute(
+        DERObjectIdentifier oid,
+        DEREncodable        attribute);
+
+    public DEREncodable getBagAttribute(
+        DERObjectIdentifier oid);
+
+    public Enumeration getBagAttributeKeys();
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java b/libcore/security/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java
new file mode 100644
index 0000000..ca3d8ea
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java
@@ -0,0 +1,302 @@
+package org.bouncycastle.jce.netscape;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERIA5String;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+
+/**
+ *
+ * 
+ * Handles NetScape certificate request (KEYGEN), these are constructed as:
+ * <pre><code>
+ *   SignedPublicKeyAndChallenge ::= SEQUENCE {
+ *     publicKeyAndChallenge    PublicKeyAndChallenge,
+ *     signatureAlgorithm       AlgorithmIdentifier,
+ *     signature                BIT STRING
+ *   }
+ * </pre>
+ *
+ * PublicKey's encoded-format has to be X.509.
+ *
+ **/
+public class NetscapeCertRequest
+    extends ASN1Encodable
+{
+    AlgorithmIdentifier    sigAlg;
+    AlgorithmIdentifier    keyAlg;
+    byte        sigBits [];
+    String challenge;
+    DERBitString content;
+    PublicKey pubkey ;
+    
+    private static ASN1Sequence getReq(
+        byte[]  r)
+        throws IOException
+    {
+        ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(r));
+
+        return ASN1Sequence.getInstance(aIn.readObject());
+    }
+
+    public NetscapeCertRequest(
+        byte[]  req)
+        throws IOException
+    {
+        this(getReq(req));
+    }
+
+    public NetscapeCertRequest (ASN1Sequence spkac)
+    {
+        try
+        {
+
+            //
+            // SignedPublicKeyAndChallenge ::= SEQUENCE {
+            //    publicKeyAndChallenge    PublicKeyAndChallenge,
+            //    signatureAlgorithm    AlgorithmIdentifier,
+            //    signature        BIT STRING
+            // }
+            //
+            if (spkac.size() != 3)
+            {
+                throw new IllegalArgumentException("invalid SPKAC (size):"
+                        + spkac.size());
+            }
+
+            sigAlg = new AlgorithmIdentifier((ASN1Sequence)spkac
+                    .getObjectAt(1));
+            sigBits = ((DERBitString)spkac.getObjectAt(2)).getBytes();
+
+            //
+            // PublicKeyAndChallenge ::= SEQUENCE {
+            //    spki            SubjectPublicKeyInfo,
+            //    challenge        IA5STRING
+            // }
+            //
+            ASN1Sequence pkac = (ASN1Sequence)spkac.getObjectAt(0);
+
+            if (pkac.size() != 2)
+            {
+                throw new IllegalArgumentException("invalid PKAC (len): "
+                        + pkac.size());
+            }
+
+            challenge = ((DERIA5String)pkac.getObjectAt(1)).getString();
+
+            //this could be dangerous, as ASN.1 decoding/encoding
+            //could potentially alter the bytes
+            content = new DERBitString(pkac);
+
+            SubjectPublicKeyInfo pubkeyinfo = new SubjectPublicKeyInfo(
+                    (ASN1Sequence)pkac.getObjectAt(0));
+
+            X509EncodedKeySpec xspec = new X509EncodedKeySpec(new DERBitString(
+                    pubkeyinfo).getBytes());
+
+            keyAlg = pubkeyinfo.getAlgorithmId();
+            pubkey = KeyFactory.getInstance(keyAlg.getObjectId().getId(), "BC")
+                    .generatePublic(xspec);
+
+        }
+        catch (Exception e)
+        {
+            throw new IllegalArgumentException(e.toString());
+        }
+    }
+
+    public NetscapeCertRequest(
+        String challenge,
+        AlgorithmIdentifier signing_alg,
+        PublicKey pub_key) throws NoSuchAlgorithmException,
+            InvalidKeySpecException, NoSuchProviderException
+    {
+
+        this.challenge = challenge;
+        sigAlg = signing_alg;
+        pubkey = pub_key;
+
+        ASN1EncodableVector content_der = new ASN1EncodableVector();
+        content_der.add(getKeySpec());
+        //content_der.add(new SubjectPublicKeyInfo(sigAlg, new RSAPublicKeyStructure(pubkey.getModulus(), pubkey.getPublicExponent()).getDERObject()));
+        content_der.add(new DERIA5String(challenge));
+
+        content = new DERBitString(new DERSequence(content_der));
+    }
+
+    public String getChallenge()
+    {
+        return challenge;
+    }
+
+    public void setChallenge(String value)
+    {
+        challenge = value;
+    }
+
+    public AlgorithmIdentifier getSigningAlgorithm()
+    {
+        return sigAlg;
+    }
+
+    public void setSigningAlgorithm(AlgorithmIdentifier value)
+    {
+        sigAlg = value;
+    }
+
+    public AlgorithmIdentifier getKeyAlgorithm()
+    {
+        return keyAlg;
+    }
+
+    public void setKeyAlgorithm(AlgorithmIdentifier value)
+    {
+        keyAlg = value;
+    }
+
+    public PublicKey getPublicKey()
+    {
+        return pubkey;
+    }
+
+    public void setPublicKey(PublicKey value)
+    {
+        pubkey = value;
+    }
+
+    public boolean verify(String challenge) throws NoSuchAlgorithmException,
+            InvalidKeyException, SignatureException, NoSuchProviderException
+    {
+        if (!challenge.equals(this.challenge))
+        {
+            return false;
+        }
+
+        //
+        // Verify the signature .. shows the response was generated
+        // by someone who knew the associated private key
+        //
+        Signature sig = Signature.getInstance(sigAlg.getObjectId().getId(),
+                "BC");
+        sig.initVerify(pubkey);
+        sig.update(content.getBytes());
+
+        return sig.verify(sigBits);
+    }
+
+    public void sign(PrivateKey priv_key) throws NoSuchAlgorithmException,
+            InvalidKeyException, SignatureException, NoSuchProviderException,
+            InvalidKeySpecException
+    {
+        sign(priv_key, null);
+    }
+
+    public void sign(PrivateKey priv_key, SecureRandom rand)
+            throws NoSuchAlgorithmException, InvalidKeyException,
+            SignatureException, NoSuchProviderException,
+            InvalidKeySpecException
+    {
+        Signature sig = Signature.getInstance(sigAlg.getObjectId().getId(),
+                "BC");
+
+        if (rand != null)
+        {
+            sig.initSign(priv_key, rand);
+        }
+        else
+        {
+            sig.initSign(priv_key);
+        }
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        DEROutputStream deros = new DEROutputStream(baos);
+
+        ASN1EncodableVector pkac = new ASN1EncodableVector();
+
+        pkac.add(getKeySpec());
+        pkac.add(new DERIA5String(challenge));
+
+        try
+        {
+            deros.writeObject(new DERSequence(pkac));
+            deros.close();
+        }
+        catch (IOException ioe)
+        {
+            throw new SignatureException(ioe.getMessage());
+        }
+
+        sig.update(baos.toByteArray());
+
+        sigBits = sig.sign();
+    }
+
+    private DERObject getKeySpec() throws NoSuchAlgorithmException,
+            InvalidKeySpecException, NoSuchProviderException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+        DERObject obj = null;
+        try
+        {
+
+            baos.write(pubkey.getEncoded());
+            baos.close();
+
+            ASN1InputStream derin = new ASN1InputStream(
+                    new ByteArrayInputStream(baos.toByteArray()));
+
+            obj = derin.readObject();
+        }
+        catch (IOException ioe)
+        {
+            throw new InvalidKeySpecException(ioe.getMessage());
+        }
+        return obj;
+    }
+
+    public DERObject toASN1Object()
+    {
+        ASN1EncodableVector spkac = new ASN1EncodableVector();
+        ASN1EncodableVector pkac = new ASN1EncodableVector();
+
+        try
+        {
+            pkac.add(getKeySpec());
+        }
+        catch (Exception e)
+        {
+            //ignore
+        }
+
+        pkac.add(new DERIA5String(challenge));
+
+        spkac.add(new DERSequence(pkac));
+        spkac.add(sigAlg);
+        spkac.add(new DERBitString(sigBits));
+
+        return new DERSequence(spkac);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/AnnotatedException.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/AnnotatedException.java
new file mode 100644
index 0000000..e68139a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/AnnotatedException.java
@@ -0,0 +1,32 @@
+package org.bouncycastle.jce.provider;
+
+public class AnnotatedException 
+    extends Exception
+{
+    private Exception _underlyingException;
+
+    AnnotatedException(
+        String string, 
+        Exception e)
+    {
+        super(string);
+        
+        _underlyingException = e;
+    }
+    
+    AnnotatedException(
+        String string)
+    {
+        this(string, null);
+    }
+
+    Exception getUnderlyingException()
+    {
+        return _underlyingException;
+    }
+    
+    public Throwable getCause()
+    {
+        return _underlyingException;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
new file mode 100644
index 0000000..5a931c2
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
@@ -0,0 +1,971 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.Provider;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.asn1.iana.IANAObjectIdentifiers;
+
+/**
+ * To add the provider at runtime use:
+ * <pre>
+ * import java.security.Security;
+ * import org.bouncycastle.jce.provider.BouncyCastleProvider;
+ *
+ * Security.addProvider(new BouncyCastleProvider());
+ * </pre>
+ * The provider can also be configured as part of your environment via
+ * static registration by adding an entry to the java.security properties
+ * file (found in $JAVA_HOME/jre/lib/security/java.security, where
+ * $JAVA_HOME is the location of your JDK/JRE distribution). You'll find
+ * detailed instructions in the file but basically it comes down to adding
+ * a line:
+ * <pre>
+ * <code>
+ *    security.provider.&lt;n&gt;=org.bouncycastle.jce.provider.BouncyCastleProvider
+ * </code>
+ * </pre>
+ * Where &lt;n&gt; is the preference you want the provider at (1 being the
+ * most prefered).
+ * <p>Note: JCE algorithm names should be uppercase only so the case insensitive
+ * test for getInstance works.
+ */
+public final class BouncyCastleProvider extends Provider
+{
+    private static String info = "BouncyCastle Security Provider v1.34";
+
+    public static String PROVIDER_NAME = "BC";
+
+    /**
+     * Construct a new provider.  This should only be required when
+     * using runtime registration of the provider using the
+     * <code>Security.addProvider()</code> mechanism.
+     */
+    public BouncyCastleProvider()
+    {
+        super(PROVIDER_NAME, 1.34, info);
+
+        //
+        // KeyStore
+        //
+        put("KeyStore.BKS", "org.bouncycastle.jce.provider.JDKKeyStore");
+        put("KeyStore.BouncyCastle", "org.bouncycastle.jce.provider.JDKKeyStore$BouncyCastleStore");
+        put("KeyStore.PKCS12", "org.bouncycastle.jce.provider.JDKPKCS12KeyStore$BCPKCS12KeyStore");
+        put("KeyStore.BCPKCS12", "org.bouncycastle.jce.provider.JDKPKCS12KeyStore$BCPKCS12KeyStore");
+        put("KeyStore.PKCS12-DEF", "org.bouncycastle.jce.provider.JDKPKCS12KeyStore$DefPKCS12KeyStore");
+        put("Alg.Alias.KeyStore.UBER", "BouncyCastle");
+        put("Alg.Alias.KeyStore.BOUNCYCASTLE", "BouncyCastle");
+        put("Alg.Alias.KeyStore.bouncycastle", "BouncyCastle");
+
+        //
+        // certificate factories.
+        //
+        put("CertificateFactory.X.509", "org.bouncycastle.jce.provider.JDKX509CertificateFactory");
+        put("Alg.Alias.CertificateFactory.X509", "X.509");
+
+        //
+        // algorithm parameter generators
+        //
+        put("AlgorithmParameterGenerator.DH", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DH");
+        put("AlgorithmParameterGenerator.DSA", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DSA");
+        // BEGIN android-removed
+        // put("AlgorithmParameterGenerator.GOST3410", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$GOST3410");
+        // put("AlgorithmParameterGenerator.ELGAMAL", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$ElGamal");
+        // END android-removed
+        put("AlgorithmParameterGenerator.DES", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DES");
+        put("AlgorithmParameterGenerator.DESEDE", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DES");
+        put("AlgorithmParameterGenerator.1.2.840.113549.3.7", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DES");
+        put("AlgorithmParameterGenerator.1.3.14.3.2.7", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$DES");
+        // BEGIN android-removed
+        // put("AlgorithmParameterGenerator.IDEA", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$IDEA");
+        // put("AlgorithmParameterGenerator.1.3.6.1.4.1.188.7.1.1.2", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$IDEA");
+        // put("AlgorithmParameterGenerator.RC2", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$RC2");
+        // put("AlgorithmParameterGenerator.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$RC2");
+        // put("AlgorithmParameterGenerator.CAST5", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$CAST5");
+        // put("AlgorithmParameterGenerator.1.2.840.113533.7.66.10", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$CAST5");
+        // END android-removed
+        put("AlgorithmParameterGenerator.AES", "org.bouncycastle.jce.provider.JDKAlgorithmParameterGenerator$AES");
+        put("Alg.Alias.AlgorithmParameterGenerator.2.16.840.1.101.3.4.2", "AES");  // these first 3 are wrong, but seem to have got around
+        put("Alg.Alias.AlgorithmParameterGenerator.2.16.840.1.101.3.4.22", "AES");
+        put("Alg.Alias.AlgorithmParameterGenerator.2.16.840.1.101.3.4.42", "AES");
+        put("Alg.Alias.AlgorithmParameterGenerator.2.16.840.1.101.3.4.1.2", "AES");
+        put("Alg.Alias.AlgorithmParameterGenerator.2.16.840.1.101.3.4.1.22", "AES");
+        put("Alg.Alias.AlgorithmParameterGenerator.2.16.840.1.101.3.4.1.42", "AES");
+        // BEGIN android-removed
+        // put("Alg.Alias.AlgorithmParameterGenerator.GOST-3410", "GOST3410");
+        // END android-removed
+        //
+        // algorithm parameters
+        //
+        put("AlgorithmParameters.OAEP", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$OAEP");
+        put("AlgorithmParameters.PSS", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$PSS");
+        put("AlgorithmParameters.DH", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$DH");
+        put("AlgorithmParameters.DSA", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$DSA");
+        // BEGIN android-removed
+        // put("AlgorithmParameters.ELGAMAL", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$ElGamal");
+        // END android-removed
+        put("AlgorithmParameters.IES", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IES");
+        put("AlgorithmParameters.PKCS12PBE", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$PKCS12PBE");
+        put("AlgorithmParameters.1.2.840.113549.3.7", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
+        // BEGIN android-removed
+        // put("AlgorithmParameters.IDEA", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IDEAAlgorithmParameters");
+        // put("AlgorithmParameters.1.3.6.1.4.1.188.7.1.1.2", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IDEAAlgorithmParameters");
+        // put("AlgorithmParameters.CAST5", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$CAST5AlgorithmParameters");
+        // put("AlgorithmParameters.1.2.840.113533.7.66.10", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$CAST5AlgorithmParameters");
+        // put("AlgorithmParameters.GOST3410", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$GOST3410");
+        // put("Alg.Alias.AlgorithmParameters.GOST-3410", "GOST3410");
+        // END android-removed
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHA1ANDRC2", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND3-KEYTRIPLEDES", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND2-KEYTRIPLEDES", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDRC2", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDRC4", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDTWOFISH", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDIDEA", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHA1ANDRC2-CBC", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND3-KEYTRIPLEDES-CBC", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND2-KEYTRIPLEDES-CBC", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDDES3KEY-CBC", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDDES2KEY-CBC", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND40BITRC2-CBC", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND40BITRC4", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND128BITRC2-CBC", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND128BITRC4", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDTWOFISH", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDIDEA", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.1", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.2", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.3", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.4", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.5", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.6", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWithSHAAnd3KeyTripleDES", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.id_RSAES_OAEP, "OAEP");
+        
+        put("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.id_RSASSA_PSS, "PSS");
+        put("Alg.Alias.AlgorithmParameters.SHA1WITHRSAANDMGF1", "PSS");
+        put("Alg.Alias.AlgorithmParameters.SHA224WITHRSAANDMGF1", "PSS");
+        put("Alg.Alias.AlgorithmParameters.SHA256WITHRSAANDMGF1", "PSS");
+        put("Alg.Alias.AlgorithmParameters.SHA384WITHRSAANDMGF1", "PSS");
+        put("Alg.Alias.AlgorithmParameters.SHA512WITHRSAANDMGF1", "PSS");
+        
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND128BITAES-CBC-BC", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND192BITAES-CBC-BC", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND256BITAES-CBC-BC", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHA256AND128BITAES-CBC-BC", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHA256AND192BITAES-CBC-BC", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHA256AND256BITAES-CBC-BC", "PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHA1AND128BITAES-CBC-BC","PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHA1AND192BITAES-CBC-BC","PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHA1AND256BITAES-CBC-BC","PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHA-1AND128BITAES-CBC-BC","PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHA-1AND192BITAES-CBC-BC","PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHA-1AND256BITAES-CBC-BC","PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHA-256AND128BITAES-CBC-BC","PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHA-256AND192BITAES-CBC-BC","PKCS12PBE");
+        put("Alg.Alias.AlgorithmParameters.PBEWITHSHA-256AND256BITAES-CBC-BC","PKCS12PBE");
+
+        put("AlgorithmParameters.SHA1WITHECDSA", "org.bouncycastle.jce.provider.JDKECDSAAlgParameters$SigAlgParameters");
+        put("AlgorithmParameters.SHA224WITHECDSA", "org.bouncycastle.jce.provider.JDKECDSAAlgParameters$SigAlgParameters");
+        put("AlgorithmParameters.SHA256WITHECDSA", "org.bouncycastle.jce.provider.JDKECDSAAlgParameters$SigAlgParameters");
+        put("AlgorithmParameters.SHA384WITHECDSA", "org.bouncycastle.jce.provider.JDKECDSAAlgParameters$SigAlgParameters");
+        put("AlgorithmParameters.SHA512WITHECDSA", "org.bouncycastle.jce.provider.JDKECDSAAlgParameters$SigAlgParameters");
+        
+        //
+        // key agreement
+        //
+        put("KeyAgreement.DH", "org.bouncycastle.jce.provider.JCEDHKeyAgreement");
+        // BEGIN android-removed
+        // put("KeyAgreement.ECDH", "org.bouncycastle.jce.provider.JCEECDHKeyAgreement$DH");
+        // put("KeyAgreement.ECDHC", "org.bouncycastle.jce.provider.JCEECDHKeyAgreement$DHC");
+        // END android-removed
+
+        //
+        // cipher engines
+        //
+        put("Cipher.DES", "org.bouncycastle.jce.provider.JCEBlockCipher$DES");
+        put("Cipher.DESEDE", "org.bouncycastle.jce.provider.JCEBlockCipher$DESede");
+        put("Cipher.1.2.840.113549.3.7", "org.bouncycastle.jce.provider.JCEBlockCipher$DESedeCBC");
+        put("Cipher.1.3.14.3.2.7", "org.bouncycastle.jce.provider.JCEBlockCipher$DESCBC");
+        put("Cipher.DESEDEWRAP", "org.bouncycastle.jce.provider.WrapCipherSpi$DESEDEWrap");
+        put("Cipher.1.2.840.113549.1.9.16.3.6", "org.bouncycastle.jce.provider.WrapCipherSpi$DESEDEWrap");
+        // BEGIN android-removed
+        // put("Cipher.SKIPJACK", "org.bouncycastle.jce.provider.JCEBlockCipher$Skipjack");
+        // put("Cipher.BLOWFISH", "org.bouncycastle.jce.provider.JCEBlockCipher$Blowfish");
+        // put("Cipher.TWOFISH", "org.bouncycastle.jce.provider.JCEBlockCipher$Twofish");
+        // put("Cipher.RC2", "org.bouncycastle.jce.provider.JCEBlockCipher$RC2");
+        // put("Cipher.RC2WRAP", "org.bouncycastle.jce.provider.WrapCipherSpi$RC2Wrap");
+        // put("Cipher.1.2.840.113549.1.9.16.3.7", "org.bouncycastle.jce.provider.WrapCipherSpi$RC2Wrap");
+        // put("Cipher.ARC4", "org.bouncycastle.jce.provider.JCEStreamCipher$RC4");
+        // put("Alg.Alias.Cipher.1.2.840.113549.3.4", "ARC4");
+        // put("Alg.Alias.Cipher.ARCFOUR", "ARC4");
+        // put("Alg.Alias.Cipher.RC4", "ARC4");
+        // put("Cipher.RC5", "org.bouncycastle.jce.provider.JCEBlockCipher$RC5");
+        // put("Cipher.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JCEBlockCipher$RC2CBC");
+        // put("Alg.Alias.Cipher.RC5-32", "RC5");
+        // put("Cipher.RC5-64", "org.bouncycastle.jce.provider.JCEBlockCipher$RC564");
+        // put("Cipher.RC6", "org.bouncycastle.jce.provider.JCEBlockCipher$RC6");
+        // AES uses some functionality from Rijdael perhaps ...  
+        // put("Cipher.RIJNDAEL", "org.bouncycastle.jce.provider.JCEBlockCipher$Rijndael");
+        // END android-removed
+        put("Cipher.AES", "org.bouncycastle.jce.provider.JCEBlockCipher$AES");
+        put("Alg.Alias.Cipher.2.16.840.1.101.3.4.2", "AES");
+        put("Alg.Alias.Cipher.2.16.840.1.101.3.4.22", "AES");
+        put("Alg.Alias.Cipher.2.16.840.1.101.3.4.42", "AES");
+        put("Cipher." + NISTObjectIdentifiers.id_aes128_ECB, "org.bouncycastle.jce.provider.JCEBlockCipher$AES");
+        put("Cipher." + NISTObjectIdentifiers.id_aes192_ECB, "org.bouncycastle.jce.provider.JCEBlockCipher$AES");
+        put("Cipher." + NISTObjectIdentifiers.id_aes256_ECB, "org.bouncycastle.jce.provider.JCEBlockCipher$AES");
+        put("Cipher." + NISTObjectIdentifiers.id_aes128_CBC, "org.bouncycastle.jce.provider.JCEBlockCipher$AESCBC");
+        put("Cipher." + NISTObjectIdentifiers.id_aes192_CBC, "org.bouncycastle.jce.provider.JCEBlockCipher$AESCBC");
+        put("Cipher." + NISTObjectIdentifiers.id_aes256_CBC, "org.bouncycastle.jce.provider.JCEBlockCipher$AESCBC");
+        put("Cipher." + NISTObjectIdentifiers.id_aes128_OFB, "org.bouncycastle.jce.provider.JCEBlockCipher$AESOFB");
+        put("Cipher." + NISTObjectIdentifiers.id_aes192_OFB, "org.bouncycastle.jce.provider.JCEBlockCipher$AESOFB");
+        put("Cipher." + NISTObjectIdentifiers.id_aes256_OFB, "org.bouncycastle.jce.provider.JCEBlockCipher$AESOFB");
+        put("Cipher." + NISTObjectIdentifiers.id_aes128_CFB, "org.bouncycastle.jce.provider.JCEBlockCipher$AESCFB");
+        put("Cipher." + NISTObjectIdentifiers.id_aes192_CFB, "org.bouncycastle.jce.provider.JCEBlockCipher$AESCFB");
+        put("Cipher." + NISTObjectIdentifiers.id_aes256_CFB, "org.bouncycastle.jce.provider.JCEBlockCipher$AESCFB");
+        put("Cipher.AESWRAP", "org.bouncycastle.jce.provider.WrapCipherSpi$AESWrap");
+        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_wrap, "AESWRAP");
+        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_wrap, "AESWRAP");
+        put("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_wrap, "AESWRAP");
+        
+        // BEGIN android-removed
+        // put("Cipher.SERPENT", "org.bouncycastle.jce.provider.JCEBlockCipher$Serpent");
+        // put("Cipher.CAMELLIA", "org.bouncycastle.jce.provider.JCEBlockCipher$Camellia");
+        // put("Cipher.CAST5", "org.bouncycastle.jce.provider.JCEBlockCipher$CAST5");
+        // put("Cipher.1.2.840.113533.7.66.10", "org.bouncycastle.jce.provider.JCEBlockCipher$CAST5CBC");
+        // put("Cipher.CAST6", "org.bouncycastle.jce.provider.JCEBlockCipher$CAST6");
+        // put("Cipher.IDEA", "org.bouncycastle.jce.provider.JCEBlockCipher$IDEA");
+        // put("Cipher.1.3.6.1.4.1.188.7.1.1.2", "org.bouncycastle.jce.provider.JCEBlockCipher$IDEACBC");
+        // END android-removed
+        put("Alg.Alias.Cipher.PBEWithSHAAnd3KeyTripleDES",  "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+
+        // BEGIN android-removed
+        // put("Cipher.GOST28147", "org.bouncycastle.jce.provider.JCEBlockCipher$GOST28147");
+        // put("Alg.Alias.Cipher.GOST", "GOST28147");
+        // put("Alg.Alias.Cipher.GOST-28147", "GOST28147");
+
+        //put("Cipher." + CryptoProObjectIdentifiers.gostR28147_cbc, "org.bouncycastle.jce.provider.JCEBlockCipher$GOST28147cbc");
+
+/*
+        put("Cipher.DES/CFB8", "org.bouncycastle.jce.provider.JCEStreamCipher$DES_CFB8");
+        put("Cipher.DESEDE/CFB8", "org.bouncycastle.jce.provider.JCEStreamCipher$DESede_CFB8");
+        put("Cipher.SKIPJACK/CFB8", "org.bouncycastle.jce.provider.JCEStreamCipher$Skipjack_CFB8");
+        put("Cipher.BLOWFISH/CFB8", "org.bouncycastle.jce.provider.JCEStreamCipher$Blowfish_CFB8");
+        put("Cipher.TWOFISH/CFB8", "org.bouncycastle.jce.provider.JCEStreamCipher$Twofish_CFB8");
+        put("Cipher.IDEA/CFB8", "org.bouncycastle.jce.provider.JCEStreamCipher$IDEA_CFB8");
+
+        put("Alg.Alias.Cipher.DES/CFB8/NOPADDING", "DES/CFB8");
+        put("Alg.Alias.Cipher.DESEDE/CFB8/NOPADDING", "DESEDE/CFB8");
+        put("Alg.Alias.Cipher.SKIPJACK/CFB8/NOPADDING", "SKIPJACK/CFB8");
+        put("Alg.Alias.Cipher.BLOWFISH/CFB8/NOPADDING", "Blowfish/CFB8");
+        put("Alg.Alias.Cipher.TWOFISH/CFB8/NOPADDING", "Twofish/CFB8");
+        put("Alg.Alias.Cipher.IDEA/CFB8/NOPADDING", "IDEA/CFB8");
+
+        put("Cipher.DES/OFB8", "org.bouncycastle.jce.provider.JCEStreamCipher$DES_OFB8");
+        put("Cipher.DESEDE/OFB8", "org.bouncycastle.jce.provider.JCEStreamCipher$DESede_OFB8");
+        put("Cipher.SKIPJACK/OFB8", "org.bouncycastle.jce.provider.JCEStreamCipher$Skipjack_OFB8");
+        put("Cipher.BLOWFISH/OFB8", "org.bouncycastle.jce.provider.JCEStreamCipher$Blowfish_OFB8");
+        put("Cipher.TWOFISH/OFB8", "org.bouncycastle.jce.provider.JCEStreamCipher$Twofish_OFB8");
+        put("Cipher.IDEA/OFB8", "org.bouncycastle.jce.provider.JCEStreamCipher$IDEA_OFB8");
+
+        put("Alg.Alias.Cipher.DES/OFB8/NOPADDING", "DES/OFB8");
+        put("Alg.Alias.Cipher.DESEDE/OFB8/NOPADDING", "DESEDE/OFB8");
+        put("Alg.Alias.Cipher.SKIPJACK/OFB8/NOPADDING", "SKIPJACK/OFB8");
+        put("Alg.Alias.Cipher.BLOWFISH/OFB8/NOPADDING", "BLOWFISH/OFB8");
+        put("Alg.Alias.Cipher.TWOFISH/OFB8/NOPADDING", "TWOFISH/OFB8");
+        put("Alg.Alias.Cipher.IDEA/OFB8/NOPADDING", "IDEA/OFB8");
+*/
+        
+        put("Cipher.RSA", "org.bouncycastle.jce.provider.JCERSACipher$NoPadding");
+        put("Cipher.RSA/RAW", "org.bouncycastle.jce.provider.JCERSACipher$NoPadding");
+        put("Cipher.RSA/PKCS1", "org.bouncycastle.jce.provider.JCERSACipher$PKCS1v1_5Padding");
+        put("Cipher.1.2.840.113549.1.1.1", "org.bouncycastle.jce.provider.JCERSACipher$PKCS1v1_5Padding");
+        put("Cipher.2.5.8.1.1", "org.bouncycastle.jce.provider.JCERSACipher$PKCS1v1_5Padding");
+        put("Cipher.RSA/1", "org.bouncycastle.jce.provider.JCERSACipher$PKCS1v1_5Padding_PrivateOnly");
+        put("Cipher.RSA/2", "org.bouncycastle.jce.provider.JCERSACipher$PKCS1v1_5Padding_PublicOnly");
+        put("Cipher.RSA/OAEP", "org.bouncycastle.jce.provider.JCERSACipher$OAEPPadding");
+        put("Cipher.1.2.840.113549.1.1.7", "org.bouncycastle.jce.provider.JCERSACipher$OAEPPadding");
+        put("Cipher.RSA/ISO9796-1", "org.bouncycastle.jce.provider.JCERSACipher$ISO9796d1Padding");
+
+        // BEGIN android-removed
+        // put("Cipher.ECIES", "org.bouncycastle.jce.provider.JCEIESCipher$ECIES");
+        // put("Cipher.BrokenECIES", "org.bouncycastle.jce.provider.JCEIESCipher$BrokenECIES");
+        // END android-removed
+        put("Cipher.IES", "org.bouncycastle.jce.provider.JCEIESCipher$IES");
+        put("Cipher.BrokenIES", "org.bouncycastle.jce.provider.JCEIESCipher$BrokenIES");
+        // BEGIN android-removed
+        // put("Cipher.ELGAMAL", "org.bouncycastle.jce.provider.JCEElGamalCipher$NoPadding");
+        // put("Cipher.ELGAMAL/PKCS1", "org.bouncycastle.jce.provider.JCEElGamalCipher$PKCS1v1_5Padding");
+        // END android-removed
+
+        put("Alg.Alias.Cipher.RSA//RAW", "RSA");
+        put("Alg.Alias.Cipher.RSA//NOPADDING", "RSA");
+        put("Alg.Alias.Cipher.RSA//PKCS1PADDING", "RSA/PKCS1");
+        put("Alg.Alias.Cipher.RSA//OAEPPADDING", "RSA/OAEP");
+        put("Alg.Alias.Cipher.RSA//ISO9796-1PADDING", "RSA/ISO9796-1");
+        
+        // BEGIN android-removed
+        // put("Alg.Alias.Cipher.ELGAMAL/ECB/PKCS1PADDING", "ELGAMAL/PKCS1");
+        // put("Alg.Alias.Cipher.ELGAMAL/NONE/PKCS1PADDING", "ELGAMAL/PKCS1");
+        // put("Alg.Alias.Cipher.ELGAMAL/NONE/NOPADDING", "ELGAMAL");
+        // END android-removed
+
+        put("Cipher.PBEWITHMD5ANDDES", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithMD5AndDES");
+        put("Cipher.BROKENPBEWITHMD5ANDDES", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithMD5AndDES");
+        put("Cipher.PBEWITHMD5ANDRC2", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithMD5AndRC2");
+        put("Cipher.PBEWITHSHA1ANDDES", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHA1AndDES");
+        put("Cipher.BROKENPBEWITHSHA1ANDDES", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithSHA1AndDES");
+        // BEGIN android-removed
+        // put("Cipher.PBEWITHSHA1ANDRC2", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHA1AndRC2");
+        // END android-removed
+        put("Cipher.PBEWITHSHAAND3-KEYTRIPLEDES-CBC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHAAndDES3Key");
+        put("Cipher.BROKENPBEWITHSHAAND3-KEYTRIPLEDES-CBC", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithSHAAndDES3Key");
+        put("Cipher.OLDPBEWITHSHAAND3-KEYTRIPLEDES-CBC", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$OldPBEWithSHAAndDES3Key");
+        put("Cipher.PBEWITHSHAAND2-KEYTRIPLEDES-CBC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHAAndDES2Key");
+        put("Cipher.BROKENPBEWITHSHAAND2-KEYTRIPLEDES-CBC", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithSHAAndDES2Key");
+        // BEGIN android-removed
+        // put("Cipher.PBEWITHSHAAND128BITRC2-CBC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHAAnd128BitRC2");
+        // put("Cipher.PBEWITHSHAAND40BITRC2-CBC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHAAnd40BitRC2");
+        // put("Cipher.PBEWITHSHAAND128BITRC4", "org.bouncycastle.jce.provider.JCEStreamCipher$PBEWithSHAAnd128BitRC4");
+        // put("Cipher.PBEWITHSHAAND40BITRC4", "org.bouncycastle.jce.provider.JCEStreamCipher$PBEWithSHAAnd40BitRC4");
+        // END android-removed
+        
+        put("Cipher.PBEWITHSHAAND128BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
+        put("Cipher.PBEWITHSHAAND192BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
+        put("Cipher.PBEWITHSHAAND256BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
+        
+        put("Alg.Alias.Cipher.PBEWITHSHA1AND3-KEYTRIPLEDES-CBC", "Cipher.PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+        put("Alg.Alias.Cipher.PBEWITHSHA1AND2-KEYTRIPLEDES-CBC", "Cipher.PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
+        // BEGIN android-removed
+        // put("Alg.Alias.Cipher.PBEWITHSHA1AND128BITRC2-CBC", "Cipher.PBEWITHSHAAND128BITRC2-CBC");
+        // put("Alg.Alias.Cipher.PBEWITHSHA1AND40BITRC2-CBC", "Cipher.PBEWITHSHAAND40BITRC2-CBC");
+        // put("Alg.Alias.Cipher.PBEWITHSHA1AND128BITRC4", "Cipher.PBEWITHSHAAND128BITRC4");
+        // put("Alg.Alias.Cipher.PBEWITHSHA1AND40BITRC4", "Cipher.PBEWITHSHAAND40BITRC4");
+        // END android-removed
+        
+        put("Cipher.PBEWITHSHAAND128BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
+        put("Cipher.PBEWITHSHAAND192BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
+        put("Cipher.PBEWITHSHAAND256BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
+        put("Cipher.PBEWITHSHA256AND128BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
+        put("Cipher.PBEWITHSHA256AND192BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
+        put("Cipher.PBEWITHSHA256AND256BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
+        put("Alg.Alias.Cipher.PBEWITHSHA1AND128BITAES-CBC-BC","PBEWITHSHAAND128BITAES-CBC-BC");
+        put("Alg.Alias.Cipher.PBEWITHSHA1AND192BITAES-CBC-BC","PBEWITHSHAAND192BITAES-CBC-BC");
+        put("Alg.Alias.Cipher.PBEWITHSHA1AND256BITAES-CBC-BC","PBEWITHSHAAND256BITAES-CBC-BC");
+        put("Alg.Alias.Cipher.PBEWITHSHA-1AND128BITAES-CBC-BC","PBEWITHSHAAND128BITAES-CBC-BC");
+        put("Alg.Alias.Cipher.PBEWITHSHA-1AND192BITAES-CBC-BC","PBEWITHSHAAND192BITAES-CBC-BC");
+        put("Alg.Alias.Cipher.PBEWITHSHA-1AND256BITAES-CBC-BC","PBEWITHSHAAND256BITAES-CBC-BC");
+        put("Alg.Alias.Cipher.PBEWITHSHA-256AND128BITAES-CBC-BC","PBEWITHSHA256AND128BITAES-CBC-BC");
+        put("Alg.Alias.Cipher.PBEWITHSHA-256AND192BITAES-CBC-BC","PBEWITHSHA256AND192BITAES-CBC-BC");
+        put("Alg.Alias.Cipher.PBEWITHSHA-256AND256BITAES-CBC-BC","PBEWITHSHA256AND256BITAES-CBC-BC");
+        
+        put("Cipher.PBEWITHMD5AND128BITAES-CBC-OPENSSL", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
+        put("Cipher.PBEWITHMD5AND192BITAES-CBC-OPENSSL", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
+        put("Cipher.PBEWITHMD5AND256BITAES-CBC-OPENSSL", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
+        
+        // BEGIN android-removed
+        // put("Cipher.PBEWITHSHAANDTWOFISH-CBC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHAAndTwofish");
+        // put("Cipher.OLDPBEWITHSHAANDTWOFISH-CBC", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$OldPBEWithSHAAndTwofish");
+        // put("Cipher.PBEWITHSHAANDIDEA-CBC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHAAndIDEA");
+        //
+        // put("Alg.Alias.Cipher.1.2.840.113549.1.12.1.1", "PBEWITHSHAAND128BITRC4");
+        // put("Alg.Alias.Cipher.1.2.840.113549.1.12.1.2", "PBEWITHSHAAND40BITRC4");
+        // END android-removed
+        put("Alg.Alias.Cipher.1.2.840.113549.1.12.1.3", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+        put("Alg.Alias.Cipher.1.2.840.113549.1.12.1.4", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
+        // BEGIN android-removed
+        // put("Alg.Alias.Cipher.1.2.840.113549.1.12.1.5", "PBEWITHSHAAND128BITRC2-CBC");
+        // put("Alg.Alias.Cipher.1.2.840.113549.1.12.1.6", "PBEWITHSHAAND40BITRC2-CBC");
+        // END android-removed
+        put("Alg.Alias.Cipher.PBEWITHSHA1ANDDESEDE", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+        //
+        // key generators.
+        //
+        put("KeyGenerator.DES", "org.bouncycastle.jce.provider.JCEKeyGenerator$DES");
+        put("Alg.Alias.KeyGenerator.1.3.14.3.2.7", "DES");
+        put("KeyGenerator.DESEDE", "org.bouncycastle.jce.provider.JCEKeyGenerator$DESede");
+        put("KeyGenerator.1.2.840.113549.3.7", "org.bouncycastle.jce.provider.JCEKeyGenerator$DESede3");
+        put("KeyGenerator.DESEDEWRAP", "org.bouncycastle.jce.provider.JCEKeyGenerator$DESede");
+        // BEGIN android-removed
+        // put("KeyGenerator.SKIPJACK", "org.bouncycastle.jce.provider.JCEKeyGenerator$Skipjack");
+        // put("KeyGenerator.BLOWFISH", "org.bouncycastle.jce.provider.JCEKeyGenerator$Blowfish");
+        // put("KeyGenerator.TWOFISH", "org.bouncycastle.jce.provider.JCEKeyGenerator$Twofish");
+        // put("KeyGenerator.RC2", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC2");
+        // put("KeyGenerator.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC2");
+        // put("KeyGenerator.RC4", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC4");
+        // put("Alg.Alias.KeyGenerator.ARC4", "RC4");
+        // put("Alg.Alias.KeyGenerator.1.2.840.113549.3.4", "RC4");
+        // put("KeyGenerator.RC5", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC5");
+        // put("Alg.Alias.KeyGenerator.RC5-32", "RC5");
+        // put("KeyGenerator.RC5-64", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC564");
+        // put("KeyGenerator.RC6", "org.bouncycastle.jce.provider.JCEKeyGenerator$RC6");
+        // put("KeyGenerator.RIJNDAEL", "org.bouncycastle.jce.provider.JCEKeyGenerator$Rijndael");
+        // END android-removed
+        put("KeyGenerator.AES", "org.bouncycastle.jce.provider.JCEKeyGenerator$AES");
+        put("KeyGenerator.2.16.840.1.101.3.4.2", "org.bouncycastle.jce.provider.JCEKeyGenerator$AES128");
+        put("KeyGenerator.2.16.840.1.101.3.4.22", "org.bouncycastle.jce.provider.JCEKeyGenerator$AES192");
+        put("KeyGenerator.2.16.840.1.101.3.4.42", "org.bouncycastle.jce.provider.JCEKeyGenerator$AES256");
+        put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_ECB, "org.bouncycastle.jce.provider.JCEKeyGenerator$AES128");
+        put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "org.bouncycastle.jce.provider.JCEKeyGenerator$AES128");
+        put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_OFB, "org.bouncycastle.jce.provider.JCEKeyGenerator$AES128");
+        put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CFB, "org.bouncycastle.jce.provider.JCEKeyGenerator$AES128");
+        put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_ECB, "org.bouncycastle.jce.provider.JCEKeyGenerator$AES192");
+        put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "org.bouncycastle.jce.provider.JCEKeyGenerator$AES192");
+        put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_OFB, "org.bouncycastle.jce.provider.JCEKeyGenerator$AES192");
+        put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CFB, "org.bouncycastle.jce.provider.JCEKeyGenerator$AES192");
+        put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_ECB, "org.bouncycastle.jce.provider.JCEKeyGenerator$AES256");
+        put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "org.bouncycastle.jce.provider.JCEKeyGenerator$AES256");
+        put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_OFB, "org.bouncycastle.jce.provider.JCEKeyGenerator$AES256");
+        put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CFB, "org.bouncycastle.jce.provider.JCEKeyGenerator$AES256");
+        put("KeyGenerator.AESWRAP", "org.bouncycastle.jce.provider.JCEKeyGenerator$AES");
+        put("KeyGenerator." + NISTObjectIdentifiers.id_aes128_wrap, "org.bouncycastle.jce.provider.JCEKeyGenerator$AES128");
+        put("KeyGenerator." + NISTObjectIdentifiers.id_aes192_wrap, "org.bouncycastle.jce.provider.JCEKeyGenerator$AES192");
+        put("KeyGenerator." + NISTObjectIdentifiers.id_aes256_wrap, "org.bouncycastle.jce.provider.JCEKeyGenerator$AES256");
+        // BEGIN android-removed
+        // put("KeyGenerator.SERPENT", "org.bouncycastle.jce.provider.JCEKeyGenerator$Serpent");
+        // put("KeyGenerator.CAMELLIA", "org.bouncycastle.jce.provider.JCEKeyGenerator$Camellia");
+        // put("KeyGenerator.CAST5", "org.bouncycastle.jce.provider.JCEKeyGenerator$CAST5");
+        // put("KeyGenerator.1.2.840.113533.7.66.10", "org.bouncycastle.jce.provider.JCEKeyGenerator$CAST5");
+        // put("KeyGenerator.CAST6", "org.bouncycastle.jce.provider.JCEKeyGenerator$CAST6");
+        // put("KeyGenerator.IDEA", "org.bouncycastle.jce.provider.JCEKeyGenerator$IDEA");
+        // put("KeyGenerator.1.3.6.1.4.1.188.7.1.1.2", "org.bouncycastle.jce.provider.JCEKeyGenerator$IDEA");
+
+        // put("KeyGenerator.GOST28147", "org.bouncycastle.jce.provider.JCEKeyGenerator$GOST28147");
+        // put("Alg.Alias.KeyGenerator.GOST", "GOST28147");
+        // put("Alg.Alias.KeyGenerator.GOST-28147", "GOST28147");
+        // put("Alg.Alias.KeyGenerator." + CryptoProObjectIdentifiers.gostR28147_cbc, "GOST28147");
+        // END android-removed
+
+        //
+        // key pair generators.
+        //
+        put("KeyPairGenerator.RSA", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$RSA");
+        put("KeyPairGenerator.DH", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$DH");
+        put("KeyPairGenerator.DSA", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$DSA");
+        // BEGIN android-removed
+        // put("KeyPairGenerator.ELGAMAL", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$ElGamal");
+        // put("KeyPairGenerator.EC", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$EC");
+        // put("KeyPairGenerator.ECDSA", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$ECDSA");
+        // put("KeyPairGenerator.ECDH", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$ECDH");
+        // put("KeyPairGenerator.ECDHC", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$ECDHC");
+        // put("KeyPairGenerator.ECIES", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$ECDH");
+        // END android-removed
+        put("Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1.1", "RSA");
+        
+        // BEGIN android-removed
+        // put("KeyPairGenerator.GOST3410", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$GOST3410");
+        // put("Alg.Alias.KeyPairGenerator.GOST-3410", "GOST3410");
+        // put("Alg.Alias.KeyPairGenerator.GOST-3410-94", "GOST3410");
+        
+        // put("KeyPairGenerator.ECGOST3410", "org.bouncycastle.jce.provider.JDKKeyPairGenerator$ECGOST3410");
+        // put("Alg.Alias.KeyPairGenerator.ECGOST-3410", "ECGOST3410");
+        // put("Alg.Alias.KeyPairGenerator.GOST-3410-2001", "ECGOST3410");
+        // END android-removed
+
+
+        //
+        // key factories
+        //
+        put("KeyFactory.RSA", "org.bouncycastle.jce.provider.JDKKeyFactory$RSA");
+        put("KeyFactory.DH", "org.bouncycastle.jce.provider.JDKKeyFactory$DH");
+        put("KeyFactory.DSA", "org.bouncycastle.jce.provider.JDKKeyFactory$DSA");
+        // BEGIN android-removed
+        // put("KeyFactory.ELGAMAL", "org.bouncycastle.jce.provider.JDKKeyFactory$ElGamal");
+        // put("KeyFactory.ElGamal", "org.bouncycastle.jce.provider.JDKKeyFactory$ElGamal");
+        // put("KeyFactory.EC", "org.bouncycastle.jce.provider.JDKKeyFactory$EC");
+        // put("KeyFactory.ECDSA", "org.bouncycastle.jce.provider.JDKKeyFactory$ECDSA");
+        // put("KeyFactory.ECDH", "org.bouncycastle.jce.provider.JDKKeyFactory$ECDH");
+        // put("KeyFactory.ECDHC", "org.bouncycastle.jce.provider.JDKKeyFactory$ECDHC");
+        // END android-removed
+        put("KeyFactory.X.509", "org.bouncycastle.jce.provider.JDKKeyFactory$X509");
+        
+        put("Alg.Alias.KeyFactory.1.2.840.113549.1.1.1", "RSA");
+        put("Alg.Alias.KeyFactory.1.2.840.10040.4.1", "DSA");
+        put("Alg.Alias.KeyFactory." + X9ObjectIdentifiers.id_ecPublicKey, "EC");
+        
+        // END android-removed
+        // put("KeyFactory.GOST3410", "org.bouncycastle.jce.provider.JDKKeyFactory$GOST3410");
+        // put("Alg.Alias.KeyFactory.GOST-3410", "GOST3410");
+        // put("Alg.Alias.KeyFactory.GOST-3410-94", "GOST3410");
+        // put("Alg.Alias.KeyFactory." + CryptoProObjectIdentifiers.gostR3410_94, "GOST3410");
+        // put("KeyFactory.ECGOST3410", "org.bouncycastle.jce.provider.JDKKeyFactory$ECGOST3410");
+        // put("Alg.Alias.KeyFactory.GOST-3410-2001", "ECGOST3410");
+        // put("Alg.Alias.KeyFactory.ECGOST-3410", "ECGOST3410");
+        // put("Alg.Alias.KeyFactory." + CryptoProObjectIdentifiers.gostR3410_2001, "ECGOST3410");
+        // END android-removed
+
+        //
+        // Algorithm parameters
+        //
+        put("AlgorithmParameters.DES", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
+        put("Alg.Alias.AlgorithmParameters.1.3.14.3.2.7", "DES");
+        put("AlgorithmParameters.DESEDE", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
+        put("AlgorithmParameters.1.2.840.113549.3.7", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
+        // BEGIN android-removed
+        // put("AlgorithmParameters.RC2", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$RC2AlgorithmParameters");
+        // put("AlgorithmParameters.1.2.840.113549.3.2", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$RC2AlgorithmParameters");
+        // put("AlgorithmParameters.RC5", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
+        // put("AlgorithmParameters.RC6", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
+        // put("AlgorithmParameters.IDEA", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IDEAAlgorithmParameters");
+        // put("AlgorithmParameters.BLOWFISH", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
+        // put("AlgorithmParameters.TWOFISH", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
+        // put("AlgorithmParameters.SKIPJACK", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
+        // put("AlgorithmParameters.RIJNDAEL", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
+        // END android-removed
+        put("AlgorithmParameters.AES", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IVAlgorithmParameters");
+        put("Alg.Alias.AlgorithmParameters.2.16.840.1.101.3.4.2", "AES");
+        put("Alg.Alias.AlgorithmParameters.2.16.840.1.101.3.4.22", "AES");
+        put("Alg.Alias.AlgorithmParameters.2.16.840.1.101.3.4.42", "AES");
+        put("Alg.Alias.AlgorithmParameters.2.16.840.1.101.3.4.1.2", "AES");
+        put("Alg.Alias.AlgorithmParameters.2.16.840.1.101.3.4.1.22", "AES");
+        put("Alg.Alias.AlgorithmParameters.2.16.840.1.101.3.4.1.42", "AES");
+        
+        //
+        // secret key factories.
+        //
+        put("SecretKeyFactory.DES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$DES");
+        put("SecretKeyFactory.DESEDE", "org.bouncycastle.jce.provider.JCESecretKeyFactory$DESede");
+        put("SecretKeyFactory.DESEDE", "org.bouncycastle.jce.provider.JCESecretKeyFactory$DESede");
+        put("SecretKeyFactory.PBEWITHMD5ANDDES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD5AndDES");
+        put("SecretKeyFactory.PBEWITHMD5ANDRC2", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD5AndRC2");
+        put("SecretKeyFactory.PBEWITHSHA1ANDDES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHA1AndDES");
+        put("SecretKeyFactory.PBEWITHSHA1ANDRC2", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHA1AndRC2");
+        put("SecretKeyFactory.PBEWITHSHAAND3-KEYTRIPLEDES-CBC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAndDES3Key");
+        put("SecretKeyFactory.PBEWITHSHAAND2-KEYTRIPLEDES-CBC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAndDES2Key");
+        // BEGIN android-removed
+        // put("SecretKeyFactory.PBEWITHSHAAND128BITRC4", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAnd128BitRC4");
+        // put("SecretKeyFactory.PBEWITHSHAAND40BITRC4", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAnd40BitRC4");
+        // put("SecretKeyFactory.PBEWITHSHAAND128BITRC2-CBC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAnd128BitRC2");
+        // put("SecretKeyFactory.PBEWITHSHAAND40BITRC2-CBC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAnd40BitRC2");
+        // put("SecretKeyFactory.PBEWITHSHAANDTWOFISH-CBC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAndTwofish");
+        // put("SecretKeyFactory.PBEWITHSHAANDIDEA-CBC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAndIDEA");
+        // put("SecretKeyFactory.PBEWITHHMACRIPEMD160", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithRIPEMD160");
+        // END android-removed
+        put("SecretKeyFactory.PBEWITHHMACSHA1", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHA");
+        // BEGIN android-removed
+        // put("SecretKeyFactory.PBEWITHHMACTIGER", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithTiger");
+        // END android-removed
+        
+        put("SecretKeyFactory.PBEWITHMD5AND128BITAES-CBC-OPENSSL", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD5And128BitAESCBCOpenSSL");
+        put("SecretKeyFactory.PBEWITHMD5AND192BITAES-CBC-OPENSSL", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD5And192BitAESCBCOpenSSL");
+        put("SecretKeyFactory.PBEWITHMD5AND256BITAES-CBC-OPENSSL", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD5And256BitAESCBCOpenSSL");
+
+        put("Alg.Alias.SecretKeyFactory.PBE", "PBE/PKCS5");
+
+        put("Alg.Alias.SecretKeyFactory.BROKENPBEWITHMD5ANDDES", "PBE/PKCS5");
+        put("Alg.Alias.SecretKeyFactory.BROKENPBEWITHSHA1ANDDES", "PBE/PKCS5");
+        put("Alg.Alias.SecretKeyFactory.OLDPBEWITHSHAAND3-KEYTRIPLEDES-CBC", "PBE/PKCS12");
+        put("Alg.Alias.SecretKeyFactory.BROKENPBEWITHSHAAND3-KEYTRIPLEDES-CBC", "PBE/PKCS12");
+        put("Alg.Alias.SecretKeyFactory.BROKENPBEWITHSHAAND2-KEYTRIPLEDES-CBC", "PBE/PKCS12");
+        // BEGIN android-removed
+        // put("Alg.Alias.SecretKeyFactory.OLDPBEWITHSHAANDTWOFISH-CBC", "PBE/PKCS12");
+
+        // put("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.1", "PBEWITHSHAAND128BITRC4");
+        // put("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.2", "PBEWITHSHAAND40BITRC4");
+        // put("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.3", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+        // put("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.4", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
+        // put("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.5", "PBEWITHSHAAND128BITRC2-CBC");
+        // put("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.6", "PBEWITHSHAAND40BITRC2-CBC");
+        // END android-removed
+
+        put("Alg.Alias.SecretKeyFactory.PBEWITHHMACSHA", "PBEWITHHMACSHA1");
+        put("Alg.Alias.SecretKeyFactory.1.3.14.3.2.26", "PBEWITHHMACSHA1");
+        put("Alg.Alias.SecretKeyFactory.PBEWithSHAAnd3KeyTripleDES", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+        
+        put("SecretKeyFactory.PBEWITHSHAAND128BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAnd128BitAESBC");
+        put("SecretKeyFactory.PBEWITHSHAAND192BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAnd192BitAESBC");
+        put("SecretKeyFactory.PBEWITHSHAAND256BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAnd256BitAESBC");
+        put("SecretKeyFactory.PBEWITHSHA256AND128BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHA256And128BitAESBC");
+        put("SecretKeyFactory.PBEWITHSHA256AND192BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHA256And192BitAESBC");
+        put("SecretKeyFactory.PBEWITHSHA256AND256BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHA256And256BitAESBC");
+        put("Alg.Alias.SecretKeyFactory.PBEWITHSHA1AND128BITAES-CBC-BC","PBEWITHSHAAND128BITAES-CBC-BC");
+        put("Alg.Alias.SecretKeyFactory.PBEWITHSHA1AND192BITAES-CBC-BC","PBEWITHSHAAND192BITAES-CBC-BC");
+        put("Alg.Alias.SecretKeyFactory.PBEWITHSHA1AND256BITAES-CBC-BC","PBEWITHSHAAND256BITAES-CBC-BC");
+        put("Alg.Alias.SecretKeyFactory.PBEWITHSHA-1AND128BITAES-CBC-BC","PBEWITHSHAAND128BITAES-CBC-BC");
+        put("Alg.Alias.SecretKeyFactory.PBEWITHSHA-1AND192BITAES-CBC-BC","PBEWITHSHAAND192BITAES-CBC-BC");
+        put("Alg.Alias.SecretKeyFactory.PBEWITHSHA-1AND256BITAES-CBC-BC","PBEWITHSHAAND256BITAES-CBC-BC");
+        put("Alg.Alias.SecretKeyFactory.PBEWITHSHA-256AND128BITAES-CBC-BC","PBEWITHSHA256AND128BITAES-CBC-BC");
+        put("Alg.Alias.SecretKeyFactory.PBEWITHSHA-256AND192BITAES-CBC-BC","PBEWITHSHA256AND192BITAES-CBC-BC");
+        put("Alg.Alias.SecretKeyFactory.PBEWITHSHA-256AND256BITAES-CBC-BC","PBEWITHSHA256AND256BITAES-CBC-BC");
+
+        addMacAlgorithms();
+
+        addMessageDigestAlgorithms();
+
+        addSignatureAlgorithms();
+
+    // Certification Path API
+        put("CertPathValidator.PKIX", "org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi");
+        put("CertPathValidator.PKIX ValidationAlgorithm", "RFC2459");
+        put("CertPathBuilder.PKIX", "org.bouncycastle.jce.provider.PKIXCertPathBuilderSpi");
+        put("CertPathBuilder.PKIX ValidationAlgorithm", "RFC2459");
+        put("CertStore.Collection", "org.bouncycastle.jce.provider.CertStoreCollectionSpi");
+    }
+    
+    //
+    // macs
+    //
+    private void addMacAlgorithms()
+    {
+        put("Mac.DESMAC", "org.bouncycastle.jce.provider.JCEMac$DES");
+        put("Alg.Alias.Mac.DES", "DESMAC");
+        put("Mac.DESMAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$DESCFB8");
+        put("Alg.Alias.Mac.DES/CFB8", "DESMAC/CFB8");
+
+        put("Mac.DESEDEMAC", "org.bouncycastle.jce.provider.JCEMac$DESede");
+        put("Alg.Alias.Mac.DESEDE", "DESEDEMAC");
+        put("Mac.DESEDEMAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$DESedeCFB8");
+        put("Alg.Alias.Mac.DESEDE/CFB8", "DESEDEMAC/CFB8");
+        
+        put("Mac.DESWITHISO9797", "org.bouncycastle.jce.provider.JCEMac$ISO9797_DES");
+        put("Alg.Alias.Mac.DESISO9797MAC", "DESWITHISO9797");
+        
+        put("Mac.DESEDEMAC64", "org.bouncycastle.jce.provider.JCEMac$DESede64");
+        put("Alg.Alias.Mac.DESEDE64", "DESEDEMAC64");
+        
+        put("Mac.ISO9797ALG3MAC", "org.bouncycastle.jce.provider.JCEMac$DES9797Alg3");
+        put("Alg.Alias.Mac.ISO9797ALG3", "ISO9797ALG3MAC");
+
+        // BEGIN android-removed
+        // put("Mac.SKIPJACKMAC", "org.bouncycastle.jce.provider.JCEMac$Skipjack");
+        // put("Alg.Alias.Mac.SKIPJACK", "SKIPJACKMAC");
+        // put("Mac.SKIPJACKMAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$SkipjackCFB8");
+        // put("Alg.Alias.Mac.SKIPJACK/CFB8", "SKIPJACKMAC/CFB8");
+        //
+        // put("Mac.IDEAMAC", "org.bouncycastle.jce.provider.JCEMac$IDEA");
+        // put("Alg.Alias.Mac.IDEA", "IDEAMAC");
+        // put("Mac.IDEAMAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$IDEACFB8");
+        // put("Alg.Alias.Mac.IDEA/CFB8", "IDEAMAC/CFB8");
+        //
+        // put("Mac.RC2MAC", "org.bouncycastle.jce.provider.JCEMac$RC2");
+        // put("Alg.Alias.Mac.RC2", "RC2MAC");
+        // put("Mac.RC2MAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$RC2CFB8");
+        // put("Alg.Alias.Mac.RC2/CFB8", "RC2MAC/CFB8");
+        //
+        // put("Mac.RC5MAC", "org.bouncycastle.jce.provider.JCEMac$RC5");
+        // put("Alg.Alias.Mac.RC5", "RC5MAC");
+        // put("Mac.RC5MAC/CFB8", "org.bouncycastle.jce.provider.JCEMac$RC5CFB8");
+        // put("Alg.Alias.Mac.RC5/CFB8", "RC5MAC/CFB8");
+        //
+        // put("Mac.GOST28147MAC", "org.bouncycastle.jce.provider.JCEMac$GOST28147");
+        //
+        // put("Mac.OLDHMACSHA384", "org.bouncycastle.jce.provider.JCEMac$OldSHA384");
+        //
+        // put("Mac.OLDHMACSHA512", "org.bouncycastle.jce.provider.JCEMac$OldSHA512");
+        //
+        //addHMACAlgorithm("MD2", "org.bouncycastle.jce.provider.JCEMac$MD2", "org.bouncycastle.jce.provider.JCEKeyGenerator$MD2HMAC");
+        //addHMACAlgorithm("MD4", "org.bouncycastle.jce.provider.JCEMac$MD4", "org.bouncycastle.jce.provider.JCEKeyGenerator$MD4HMAC");
+        // END android-removed
+        addHMACAlgorithm("MD5", "org.bouncycastle.jce.provider.JCEMac$MD5", "org.bouncycastle.jce.provider.JCEKeyGenerator$MD5HMAC");
+        addHMACAlias("MD5", IANAObjectIdentifiers.hmacMD5);
+
+        addHMACAlgorithm("SHA1", "org.bouncycastle.jce.provider.JCEMac$SHA1", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACSHA1");
+        addHMACAlias("SHA1", PKCSObjectIdentifiers.id_hmacWithSHA1);
+        addHMACAlias("SHA1", IANAObjectIdentifiers.hmacSHA1);
+        addHMACAlgorithm("SHA224", "org.bouncycastle.jce.provider.JCEMac$SHA224", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACSHA224");
+        addHMACAlias("SHA224", PKCSObjectIdentifiers.id_hmacWithSHA224);
+        addHMACAlgorithm("SHA256", "org.bouncycastle.jce.provider.JCEMac$SHA256", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACSHA256");
+        addHMACAlias("SHA256", PKCSObjectIdentifiers.id_hmacWithSHA256);
+        addHMACAlgorithm("SHA384", "org.bouncycastle.jce.provider.JCEMac$SHA384", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACSHA384");
+        addHMACAlias("SHA384", PKCSObjectIdentifiers.id_hmacWithSHA384);
+        addHMACAlgorithm("SHA512", "org.bouncycastle.jce.provider.JCEMac$SHA512", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACSHA512");
+        addHMACAlias("SHA512", PKCSObjectIdentifiers.id_hmacWithSHA512);
+
+        // BEGIN android-removed
+        //addHMACAlgorithm("RIPEMD128", "org.bouncycastle.jce.provider.JCEMac$RIPEMD128", "org.bouncycastle.jce.provider.JCEKeyGenerator$RIPEMD128HMAC");
+        //addHMACAlgorithm("RIPEMD160", "org.bouncycastle.jce.provider.JCEMac$RIPEMD160", "org.bouncycastle.jce.provider.JCEKeyGenerator$RIPEMD160HMAC");
+        //addHMACAlias("RIPEMD160", IANAObjectIdentifiers.hmacRIPEMD160);
+
+        // addHMACAlgorithm("TIGER", "org.bouncycastle.jce.provider.JCEMac$Tiger", "org.bouncycastle.jce.provider.JCEKeyGenerator$HMACTIGER");
+        // addHMACAlias("TIGER", IANAObjectIdentifiers.hmacTIGER);
+        // END android-removed
+
+        put("Mac.PBEWITHHMACSHA", "org.bouncycastle.jce.provider.JCEMac$PBEWithSHA");
+        put("Mac.PBEWITHHMACSHA1", "org.bouncycastle.jce.provider.JCEMac$PBEWithSHA");
+        // BEGIN android-removed
+        // put("Mac.PBEWITHHMACRIPEMD160", "org.bouncycastle.jce.provider.JCEMac$PBEWithRIPEMD160");
+        // END android-removed
+        put("Alg.Alias.Mac.1.3.14.3.2.26", "PBEWITHHMACSHA");
+    }
+
+    private void addHMACAlgorithm(
+        String algorithm,
+        String algorithmClassName,
+        String keyGeneratorClassName)
+    {
+        String mainName = "HMAC" + algorithm;
+
+        put("Mac." + mainName, algorithmClassName);
+        put("Alg.Alias.Mac.HMAC-" + algorithm, mainName);
+        put("Alg.Alias.Mac.HMAC/" + algorithm, mainName);
+        put("KeyGenerator." + mainName, keyGeneratorClassName);
+        put("Alg.Alias.KeyGenerator.HMAC-" + algorithm, mainName);
+        put("Alg.Alias.KeyGenerator.HMAC/" + algorithm, mainName);
+    }
+
+    private void addHMACAlias(
+        String              algorithm,
+        DERObjectIdentifier oid)
+    {
+        String mainName = "HMAC" + algorithm;
+
+        put("Alg.Alias.Mac." + oid, mainName);
+        put("Alg.Alias.KeyGenerator." + oid, mainName);
+    }
+
+    //
+    // message digests
+    //
+    private void addMessageDigestAlgorithms()
+    {
+        put("MessageDigest.SHA-1", "org.bouncycastle.jce.provider.JDKMessageDigest$SHA1");
+        put("Alg.Alias.MessageDigest.SHA1", "SHA-1");
+        put("Alg.Alias.MessageDigest.SHA", "SHA-1");
+        put("Alg.Alias.MessageDigest." + OIWObjectIdentifiers.idSHA1, "SHA-1");
+        put("MessageDigest.SHA-224", "org.bouncycastle.jce.provider.JDKMessageDigest$SHA224");
+        put("Alg.Alias.MessageDigest.SHA224", "SHA-224");
+        put("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha224, "SHA-224");
+        put("MessageDigest.SHA-256", "org.bouncycastle.jce.provider.JDKMessageDigest$SHA256");
+        put("Alg.Alias.MessageDigest.SHA256", "SHA-256");
+        put("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha256, "SHA-256");
+        put("MessageDigest.SHA-384", "org.bouncycastle.jce.provider.JDKMessageDigest$SHA384");
+        put("Alg.Alias.MessageDigest.SHA384", "SHA-384");
+        put("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha384, "SHA-384");
+        put("MessageDigest.SHA-512", "org.bouncycastle.jce.provider.JDKMessageDigest$SHA512");
+        put("Alg.Alias.MessageDigest.SHA512", "SHA-512");
+        put("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha512, "SHA-512");
+        
+        // BEGIN android-removed
+        // put("MessageDigest.MD2", "org.bouncycastle.jce.provider.JDKMessageDigest$MD2");
+        // put("Alg.Alias.MessageDigest." + PKCSObjectIdentifiers.md2, "MD2");
+        // put("MessageDigest.MD4", "org.bouncycastle.jce.provider.JDKMessageDigest$MD4");
+        // put("Alg.Alias.MessageDigest." + PKCSObjectIdentifiers.md4, "MD4");
+        // END android-removed
+        put("MessageDigest.MD5", "org.bouncycastle.jce.provider.JDKMessageDigest$MD5");
+        put("Alg.Alias.MessageDigest." + PKCSObjectIdentifiers.md5, "MD5");
+        // BEGIN android-removed
+        // put("MessageDigest.RIPEMD128", "org.bouncycastle.jce.provider.JDKMessageDigest$RIPEMD128");
+        // put("Alg.Alias.MessageDigest." + TeleTrusTObjectIdentifiers.ripemd128, "RIPEMD128");
+        // put("MessageDigest.RIPEMD160", "org.bouncycastle.jce.provider.JDKMessageDigest$RIPEMD160");
+        // put("Alg.Alias.MessageDigest." + TeleTrusTObjectIdentifiers.ripemd160, "RIPEMD160");
+        // put("MessageDigest.RIPEMD256", "org.bouncycastle.jce.provider.JDKMessageDigest$RIPEMD256");
+        // put("Alg.Alias.MessageDigest." + TeleTrusTObjectIdentifiers.ripemd256, "RIPEMD256");
+        // put("MessageDigest.RIPEMD320", "org.bouncycastle.jce.provider.JDKMessageDigest$RIPEMD320");
+        // put("MessageDigest.Tiger", "org.bouncycastle.jce.provider.JDKMessageDigest$Tiger");
+        
+        // put("MessageDigest.WHIRLPOOL", "org.bouncycastle.jce.provider.JDKMessageDigest$Whirlpool");
+        
+        // put("MessageDigest.GOST3411", "org.bouncycastle.jce.provider.JDKMessageDigest$GOST3411");
+        // put("Alg.Alias.MessageDigest.GOST", "GOST3411");
+        // put("Alg.Alias.MessageDigest.GOST-3411", "GOST3411");
+        // put("Alg.Alias.MessageDigest." + CryptoProObjectIdentifiers.gostR3411, "GOST3411");
+        // END android-removed
+    }
+    
+    //
+    // signature algorithms.
+    //
+    private void addSignatureAlgorithms()
+    {
+        put("Signature.MD2WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$MD2WithRSAEncryption");
+        put("Signature.MD4WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$MD4WithRSAEncryption");
+        put("Signature.MD5WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$MD5WithRSAEncryption");
+        put("Signature.SHA1WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$SHA1WithRSAEncryption");
+        put("Signature.SHA224WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$SHA224WithRSAEncryption");
+        put("Signature.SHA256WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$SHA256WithRSAEncryption");
+        put("Signature.SHA384WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$SHA384WithRSAEncryption");
+        put("Signature.SHA512WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$SHA512WithRSAEncryption");
+        // BEGIN android-removed
+        // put("Signature.RIPEMD160WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$RIPEMD160WithRSAEncryption");
+        // put("Signature.RIPEMD128WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$RIPEMD128WithRSAEncryption");
+        // put("Signature.RIPEMD256WithRSAEncryption", "org.bouncycastle.jce.provider.JDKDigestSignature$RIPEMD256WithRSAEncryption");
+        // END android-removed
+        put("Signature.DSA", "org.bouncycastle.jce.provider.JDKDSASigner$stdDSA");
+        put("Signature.NONEWITHDSA", "org.bouncycastle.jce.provider.JDKDSASigner$noneDSA");
+        // BEGIN android-removed
+        // put("Signature.ECDSA", "org.bouncycastle.jce.provider.JDKDSASigner$ecDSA");
+        // put("Signature.SHA1WITHECNR", "org.bouncycastle.jce.provider.JDKDSASigner$ecNR");
+        // put("Signature.SHA224WITHECNR", "org.bouncycastle.jce.provider.JDKDSASigner$ecNR224");
+        // put("Signature.SHA256WITHECNR", "org.bouncycastle.jce.provider.JDKDSASigner$ecNR256");
+        // put("Signature.SHA384WITHECNR", "org.bouncycastle.jce.provider.JDKDSASigner$ecNR384");
+        // put("Signature.SHA512WITHECNR", "org.bouncycastle.jce.provider.JDKDSASigner$ecNR512");
+        // END android-removed
+        put("Signature.SHA1withRSA/ISO9796-2", "org.bouncycastle.jce.provider.JDKISOSignature$SHA1WithRSAEncryption");
+        put("Signature.MD5withRSA/ISO9796-2", "org.bouncycastle.jce.provider.JDKISOSignature$MD5WithRSAEncryption");
+        // BEGIN android-removed
+        // put("Signature.RIPEMD160withRSA/ISO9796-2", "org.bouncycastle.jce.provider.JDKISOSignature$RIPEMD160WithRSAEncryption");
+        // END android-removed
+
+        put("Signature.RSASSA-PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$PSSwithRSA");
+        put("Signature." + PKCSObjectIdentifiers.id_RSASSA_PSS, "org.bouncycastle.jce.provider.JDKPSSSigner$PSSwithRSA");
+        put("Signature.SHA1withRSA/PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$SHA1withRSA");
+        put("Signature.SHA224withRSA/PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$SHA224withRSA");
+        put("Signature.SHA256withRSA/PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$SHA256withRSA");
+        put("Signature.SHA384withRSA/PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$SHA384withRSA");
+        put("Signature.SHA512withRSA/PSS", "org.bouncycastle.jce.provider.JDKPSSSigner$SHA512withRSA");
+
+        put("Alg.Alias.Signature.RAWDSA", "NONEWITHDSA");
+        
+        put("Alg.Alias.Signature.SHA1withRSAandMGF1", "SHA1withRSA/PSS");
+        put("Alg.Alias.Signature.SHA224withRSAandMGF1", "SHA224withRSA/PSS");
+        put("Alg.Alias.Signature.SHA256withRSAandMGF1", "SHA256withRSA/PSS");
+        put("Alg.Alias.Signature.SHA384withRSAandMGF1", "SHA384withRSA/PSS");
+        put("Alg.Alias.Signature.SHA512withRSAandMGF1", "SHA512withRSA/PSS");
+        
+        put("Alg.Alias.Signature.MD2withRSAEncryption", "MD2WithRSAEncryption");
+        put("Alg.Alias.Signature.MD4withRSAEncryption", "MD4WithRSAEncryption");
+        put("Alg.Alias.Signature.MD5withRSAEncryption", "MD5WithRSAEncryption");
+        put("Alg.Alias.Signature.SHA1withRSAEncryption", "SHA1WithRSAEncryption");
+        put("Alg.Alias.Signature.SHA224withRSAEncryption", "SHA224WithRSAEncryption");
+
+        put("Alg.Alias.Signature.SHA256withRSAEncryption", "SHA256WithRSAEncryption");
+        put("Alg.Alias.Signature.SHA384withRSAEncryption", "SHA384WithRSAEncryption");
+        put("Alg.Alias.Signature.SHA512withRSAEncryption", "SHA512WithRSAEncryption");
+
+        put("Alg.Alias.Signature.SHA256WithRSAEncryption", "SHA256WithRSAEncryption");
+        put("Alg.Alias.Signature.SHA384WithRSAEncryption", "SHA384WithRSAEncryption");
+        put("Alg.Alias.Signature.SHA512WithRSAEncryption", "SHA512WithRSAEncryption");
+
+        put("Alg.Alias.Signature.SHA256WITHRSAENCRYPTION", "SHA256WithRSAEncryption");
+        put("Alg.Alias.Signature.SHA384WITHRSAENCRYPTION", "SHA384WithRSAEncryption");
+        put("Alg.Alias.Signature.SHA512WITHRSAENCRYPTION", "SHA512WithRSAEncryption");
+
+        // BEGIN android-removed
+        // put("Alg.Alias.Signature.RIPEMD160withRSAEncryption", "RIPEMD160WithRSAEncryption");
+        // END android-removed
+        put("Alg.Alias.Signature." + PKCSObjectIdentifiers.md2WithRSAEncryption, "MD2WithRSAEncryption");
+        put("Alg.Alias.Signature.MD2WithRSA", "MD2WithRSAEncryption");
+        put("Alg.Alias.Signature.MD2withRSA", "MD2WithRSAEncryption");
+        put("Alg.Alias.Signature.MD2/RSA", "MD2WithRSAEncryption");
+        put("Alg.Alias.Signature.MD5WithRSA", "MD5WithRSAEncryption");
+        put("Alg.Alias.Signature.MD5withRSA", "MD5WithRSAEncryption");
+        put("Alg.Alias.Signature.MD5/RSA", "MD5WithRSAEncryption");
+        put("Alg.Alias.Signature." + PKCSObjectIdentifiers.md5WithRSAEncryption, "MD5WithRSAEncryption");
+        put("Alg.Alias.Signature.MD4WithRSA", "MD4WithRSAEncryption");
+        put("Alg.Alias.Signature.MD4withRSA", "MD4WithRSAEncryption");
+        put("Alg.Alias.Signature.MD4/RSA", "MD4WithRSAEncryption");
+        put("Alg.Alias.Signature." + PKCSObjectIdentifiers.md4WithRSAEncryption, "MD4WithRSAEncryption");
+        put("Alg.Alias.Signature.SHA1WithRSA", "SHA1WithRSAEncryption");
+        put("Alg.Alias.Signature.SHA1withRSA", "SHA1WithRSAEncryption");
+        put("Alg.Alias.Signature.SHA224WithRSA", "SHA224WithRSAEncryption");
+        put("Alg.Alias.Signature.SHA224withRSA", "SHA224WithRSAEncryption");
+        put("Alg.Alias.Signature.SHA256WithRSA", "SHA256WithRSAEncryption");
+        put("Alg.Alias.Signature.SHA256withRSA", "SHA256WithRSAEncryption");
+        put("Alg.Alias.Signature.SHA384WithRSA", "SHA384WithRSAEncryption");
+        put("Alg.Alias.Signature.SHA384withRSA", "SHA384WithRSAEncryption");
+        put("Alg.Alias.Signature.SHA512WithRSA", "SHA512WithRSAEncryption");
+        put("Alg.Alias.Signature.SHA512withRSA", "SHA512WithRSAEncryption");
+        put("Alg.Alias.Signature.SHA1/RSA", "SHA1WithRSAEncryption");
+        put("Alg.Alias.Signature.SHA-1/RSA", "SHA1WithRSAEncryption");
+        put("Alg.Alias.Signature." + PKCSObjectIdentifiers.sha1WithRSAEncryption, "SHA1WithRSAEncryption");
+        put("Alg.Alias.Signature." + PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WithRSAEncryption");
+        put("Alg.Alias.Signature." + PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WithRSAEncryption");
+        put("Alg.Alias.Signature." + PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WithRSAEncryption");
+        put("Alg.Alias.Signature." + PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WithRSAEncryption");
+        put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.1", "SHA1WithRSAEncryption");
+        put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.5", "SHA1WithRSAEncryption");
+        put("Alg.Alias.Signature.1.2.840.113549.2.5with1.2.840.113549.1.1.1", "MD5WithRSAEncryption");
+        // BEGIN android-removed
+        // put("Alg.Alias.Signature.RIPEMD160WithRSA", "RIPEMD160WithRSAEncryption");
+        // put("Alg.Alias.Signature.RIPEMD160withRSA", "RIPEMD160WithRSAEncryption");
+        // put("Alg.Alias.Signature.RIPEMD128WithRSA", "RIPEMD128WithRSAEncryption");
+        // put("Alg.Alias.Signature.RIPEMD128withRSA", "RIPEMD128WithRSAEncryption");
+        // put("Alg.Alias.Signature.RIPEMD256WithRSA", "RIPEMD256WithRSAEncryption");
+        // put("Alg.Alias.Signature.RIPEMD256withRSA", "RIPEMD256WithRSAEncryption");
+        // put("Alg.Alias.Signature.RIPEMD-160/RSA", "RIPEMD160WithRSAEncryption");
+        // put("Alg.Alias.Signature.RMD160withRSA", "RIPEMD160WithRSAEncryption");
+        // put("Alg.Alias.Signature.RMD160/RSA", "RIPEMD160WithRSAEncryption");
+        // put("Alg.Alias.Signature.1.3.36.3.3.1.2", "RIPEMD160WithRSAEncryption");
+        // put("Alg.Alias.Signature.1.3.36.3.3.1.3", "RIPEMD128WithRSAEncryption");
+        // put("Alg.Alias.Signature.1.3.36.3.3.1.4", "RIPEMD256WithRSAEncryption");
+        // END android-removed
+        put("Alg.Alias.Signature." + OIWObjectIdentifiers.sha1WithRSA, "SHA1WithRSAEncryption");
+        
+        put("Alg.Alias.Signature.MD2WITHRSAENCRYPTION", "MD2WithRSAEncryption");
+        put("Alg.Alias.Signature.MD5WITHRSAENCRYPTION", "MD5WithRSAEncryption");
+        put("Alg.Alias.Signature.SHA1WITHRSAENCRYPTION", "SHA1WithRSAEncryption");
+        // BEGIN android-removed
+        // put("Alg.Alias.Signature.RIPEMD160WITHRSAENCRYPTION", "RIPEMD160WithRSAEncryption");
+        // END android-removed
+
+        put("Alg.Alias.Signature.MD5WITHRSA", "MD5WithRSAEncryption");
+        put("Alg.Alias.Signature.SHA1WITHRSA", "SHA1WithRSAEncryption");
+        // BEGIN android-removed
+        // put("Alg.Alias.Signature.RIPEMD160WITHRSA", "RIPEMD160WithRSAEncryption");
+        // END android-removed
+        put("Alg.Alias.Signature.RMD160WITHRSA", "RIPEMD160WithRSAEncryption");
+        // BEGIN android-removed
+        // put("Alg.Alias.Signature.RIPEMD160WITHRSA", "RIPEMD160WithRSAEncryption");
+
+        // put("Alg.Alias.Signature.SHA1withECDSA", "ECDSA");
+        // put("Alg.Alias.Signature.ECDSAwithSHA1", "ECDSA");
+        // put("Alg.Alias.Signature.SHA1WITHECDSA", "ECDSA");
+        // put("Alg.Alias.Signature.ECDSAWITHSHA1", "ECDSA");
+        // put("Alg.Alias.Signature.SHA1WithECDSA", "ECDSA");
+        // put("Alg.Alias.Signature.ECDSAWithSHA1", "ECDSA");
+        // put("Alg.Alias.Signature.1.2.840.10045.4.1", "ECDSA");
+
+        // addSignatureAlgorithm("SHA224", "ECDSA", "org.bouncycastle.jce.provider.JDKDSASigner$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224);
+        // addSignatureAlgorithm("SHA256", "ECDSA", "org.bouncycastle.jce.provider.JDKDSASigner$ecDSA256", X9ObjectIdentifiers.ecdsa_with_SHA256);
+        // addSignatureAlgorithm("SHA384", "ECDSA", "org.bouncycastle.jce.provider.JDKDSASigner$ecDSA384", X9ObjectIdentifiers.ecdsa_with_SHA384);
+        // addSignatureAlgorithm("SHA512", "ECDSA", "org.bouncycastle.jce.provider.JDKDSASigner$ecDSA512", X9ObjectIdentifiers.ecdsa_with_SHA512);
+        // END android-removed
+
+        put("Alg.Alias.Signature.SHA/DSA", "DSA");
+        put("Alg.Alias.Signature.SHA1withDSA", "DSA");
+        put("Alg.Alias.Signature.SHA1WITHDSA", "DSA");
+        put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.1", "DSA");
+        put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.3", "DSA");
+        put("Alg.Alias.Signature.DSAwithSHA1", "DSA");
+        put("Alg.Alias.Signature.DSAWITHSHA1", "DSA");
+        put("Alg.Alias.Signature.SHA1WithDSA", "DSA");
+        put("Alg.Alias.Signature.DSAWithSHA1", "DSA");
+        put("Alg.Alias.Signature.1.2.840.10040.4.3", "DSA");
+        put("Alg.Alias.Signature.MD5WithRSA/ISO9796-2", "MD5withRSA/ISO9796-2");
+        put("Alg.Alias.Signature.SHA1WithRSA/ISO9796-2", "SHA1withRSA/ISO9796-2");
+        // BEGIN android-removed
+        // put("Alg.Alias.Signature.RIPEMD160WithRSA/ISO9796-2", "RIPEMD160withRSA/ISO9796-2");
+        
+        // put("Signature.ECGOST3410", "org.bouncycastle.jce.provider.JDKGOST3410Signer$ecgost3410");
+        // put("Alg.Alias.Signature.ECGOST-3410", "ECGOST3410");
+        // put("Alg.Alias.Signature.GOST-3410-2001", "ECGOST3410");
+        // put("Alg.Alias.Signature.GOST3411withECGOST3410", "ECGOST3410");
+        // put("Alg.Alias.Signature.GOST3411WITHECGOST3410", "ECGOST3410");
+        // put("Alg.Alias.Signature.GOST3411WithECGOST3410", "ECGOST3410");
+        // put("Alg.Alias.Signature." + CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "ECGOST3410");
+        
+        // put("Signature.GOST3410", "org.bouncycastle.jce.provider.JDKGOST3410Signer$gost3410");
+        // put("Alg.Alias.Signature.GOST-3410", "GOST3410");
+        // put("Alg.Alias.Signature.GOST-3410-94", "GOST3410");
+        // put("Alg.Alias.Signature.GOST3411withGOST3410", "GOST3410");
+        // put("Alg.Alias.Signature.GOST3411WITHGOST3410", "GOST3410");
+        // put("Alg.Alias.Signature.GOST3411WithGOST3410", "GOST3410");
+        // put("Alg.Alias.Signature." + CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3410");
+        // END android-removed
+    }
+
+    private void addSignatureAlgorithm(
+        String digest,
+        String algorithm,
+        String className,
+        DERObjectIdentifier oid)
+    {
+        String mainName = digest + "WITH" + algorithm;
+        String jdk11Variation1 = digest + "with" + algorithm;
+        String jdk11Variation2 = digest + "With" + algorithm;
+        String alias = digest + "/" + algorithm;
+
+        put("Signature." + mainName, className);
+        put("Alg.Alias.Signature." + jdk11Variation1, mainName);
+        put("Alg.Alias.Signature." + jdk11Variation2, mainName);
+        put("Alg.Alias.Signature." + alias, mainName);
+        put("Alg.Alias.Signature." + oid, mainName);
+        put("Alg.Alias.Signature.OID." + oid, mainName);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/BrokenJCEBlockCipher.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/BrokenJCEBlockCipher.java
new file mode 100644
index 0000000..a1350b2
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/BrokenJCEBlockCipher.java
@@ -0,0 +1,624 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+import javax.crypto.spec.RC5ParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.BufferedBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.engines.DESEngine;
+import org.bouncycastle.crypto.engines.DESedeEngine;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.engines.TwofishEngine;
+// END android-removed
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.modes.CFBBlockCipher;
+import org.bouncycastle.crypto.modes.CTSBlockCipher;
+import org.bouncycastle.crypto.modes.OFBBlockCipher;
+import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.crypto.params.RC2Parameters;
+import org.bouncycastle.crypto.params.RC5Parameters;
+import org.bouncycastle.util.Strings;
+
+public class BrokenJCEBlockCipher
+    implements BrokenPBE
+{
+    //
+    // specs we can handle.
+    //
+    private Class[]                 availableSpecs =
+                                    {
+                                        IvParameterSpec.class,
+                                        PBEParameterSpec.class,
+                                        RC2ParameterSpec.class,
+                                        RC5ParameterSpec.class
+                                    };
+ 
+    private BufferedBlockCipher     cipher;
+    private ParametersWithIV        ivParam;
+
+    private int                     pbeType = PKCS12;
+    private int                     pbeHash = SHA1;
+    private int                     pbeKeySize;
+    private int                     pbeIvSize;
+
+    private int                     ivLength = 0;
+
+    private AlgorithmParameters     engineParams = null;
+
+    protected BrokenJCEBlockCipher(
+        BlockCipher engine)
+    {
+        cipher = new PaddedBufferedBlockCipher(engine);
+    }
+        
+    protected BrokenJCEBlockCipher(
+        BlockCipher engine,
+        int         pbeType,
+        int         pbeHash,
+        int         pbeKeySize,
+        int         pbeIvSize)
+    {
+        cipher = new PaddedBufferedBlockCipher(engine);
+
+        this.pbeType = pbeType;
+        this.pbeHash = pbeHash;
+        this.pbeKeySize = pbeKeySize;
+        this.pbeIvSize = pbeIvSize;
+    }
+
+    protected int engineGetBlockSize() 
+    {
+        return cipher.getBlockSize();
+    }
+
+    protected byte[] engineGetIV() 
+    {
+        return (ivParam != null) ? ivParam.getIV() : null;
+    }
+
+    protected int engineGetKeySize(
+        Key     key) 
+    {
+        return key.getEncoded().length;
+    }
+
+    protected int engineGetOutputSize(
+        int     inputLen) 
+    {
+        return cipher.getOutputSize(inputLen);
+    }
+
+    protected AlgorithmParameters engineGetParameters() 
+    {
+        if (engineParams == null)
+        {
+            if (ivParam != null)
+            {
+                String  name = cipher.getUnderlyingCipher().getAlgorithmName();
+
+                if (name.indexOf('/') >= 0)
+                {
+                    name = name.substring(0, name.indexOf('/'));
+                }
+
+                try
+                {
+                    engineParams = AlgorithmParameters.getInstance(name, "BC");
+                    engineParams.init(ivParam.getIV());
+                }
+                catch (Exception e)
+                {
+                    throw new RuntimeException(e.toString());
+                }
+            }
+        }
+
+        return engineParams;
+    }
+
+    protected void engineSetMode(
+        String  mode) 
+    {
+        String  modeName = Strings.toUpperCase(mode);
+
+        if (modeName.equals("ECB"))
+        {
+            ivLength = 0;
+            cipher = new PaddedBufferedBlockCipher(cipher.getUnderlyingCipher());
+        }
+        else if (modeName.equals("CBC"))
+        {
+            ivLength = cipher.getUnderlyingCipher().getBlockSize();
+            cipher = new PaddedBufferedBlockCipher(
+                            new CBCBlockCipher(cipher.getUnderlyingCipher()));
+        }
+        else if (modeName.startsWith("OFB"))
+        {
+            ivLength = cipher.getUnderlyingCipher().getBlockSize();
+            if (modeName.length() != 3)
+            {
+                int wordSize = Integer.parseInt(modeName.substring(3));
+
+                cipher = new PaddedBufferedBlockCipher(
+                                new OFBBlockCipher(cipher.getUnderlyingCipher(), wordSize));
+            }
+            else
+            {
+                cipher = new PaddedBufferedBlockCipher(
+                        new OFBBlockCipher(cipher.getUnderlyingCipher(), 8 * cipher.getBlockSize()));
+            }
+        }
+        else if (modeName.startsWith("CFB"))
+        {
+            ivLength = cipher.getUnderlyingCipher().getBlockSize();
+            if (modeName.length() != 3)
+            {
+                int wordSize = Integer.parseInt(modeName.substring(3));
+
+                cipher = new PaddedBufferedBlockCipher(
+                                new CFBBlockCipher(cipher.getUnderlyingCipher(), wordSize));
+            }
+            else
+            {
+                cipher = new PaddedBufferedBlockCipher(
+                        new CFBBlockCipher(cipher.getUnderlyingCipher(), 8 * cipher.getBlockSize()));
+            }
+        }
+        else
+        {
+            throw new IllegalArgumentException("can't support mode " + mode);
+        }
+    }
+
+    protected void engineSetPadding(
+        String  padding) 
+    throws NoSuchPaddingException
+    {
+        String  paddingName = Strings.toUpperCase(padding);
+
+        if (paddingName.equals("NOPADDING"))
+        {
+            cipher = new BufferedBlockCipher(cipher.getUnderlyingCipher());
+        }
+        else if (paddingName.equals("PKCS5PADDING") || paddingName.equals("PKCS7PADDING") || paddingName.equals("ISO10126PADDING"))
+        {
+            cipher = new PaddedBufferedBlockCipher(cipher.getUnderlyingCipher());
+        }
+        else if (paddingName.equals("WITHCTS"))
+        {
+            cipher = new CTSBlockCipher(cipher.getUnderlyingCipher());
+        }
+        else
+        {
+            throw new NoSuchPaddingException("Padding " + padding + " unknown.");
+        }
+    }
+
+    protected void engineInit(
+        int                     opmode,
+        Key                     key,
+        AlgorithmParameterSpec  params,
+        SecureRandom            random) 
+    throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        CipherParameters        param;
+
+        //
+        // a note on iv's - if ivLength is zero the IV gets ignored (we don't use it).
+        //
+        if (key instanceof JCEPBEKey)
+        {
+            param = BrokenPBE.Util.makePBEParameters((JCEPBEKey)key, params, pbeType, pbeHash,
+                        cipher.getUnderlyingCipher().getAlgorithmName(), pbeKeySize, pbeIvSize);
+
+            if (pbeIvSize != 0)
+            {
+                ivParam = (ParametersWithIV)param;
+            }
+        }
+        else if (params == null)
+        {
+            param = new KeyParameter(key.getEncoded());
+        }
+        else if (params instanceof IvParameterSpec)
+        {
+            if (ivLength != 0)
+            {
+                param = new ParametersWithIV(new KeyParameter(key.getEncoded()), ((IvParameterSpec)params).getIV());
+                ivParam = (ParametersWithIV)param;
+            }
+            else
+            {
+                param = new KeyParameter(key.getEncoded());
+            }
+        }
+        else if (params instanceof RC2ParameterSpec)
+        {
+            RC2ParameterSpec    rc2Param = (RC2ParameterSpec)params;
+
+            param = new RC2Parameters(key.getEncoded(), ((RC2ParameterSpec)params).getEffectiveKeyBits());
+
+            if (rc2Param.getIV() != null && ivLength != 0)
+            {
+                param = new ParametersWithIV(param, rc2Param.getIV());
+                ivParam = (ParametersWithIV)param;
+            }
+        }
+        else if (params instanceof RC5ParameterSpec)
+        {
+            RC5ParameterSpec    rc5Param = (RC5ParameterSpec)params;
+
+            param = new RC5Parameters(key.getEncoded(), ((RC5ParameterSpec)params).getRounds());
+            if (rc5Param.getWordSize() != 32)
+            {
+                throw new IllegalArgumentException("can only accept RC5 word size 32 (at the moment...)");
+            }
+            if ((rc5Param.getIV() != null) && (ivLength != 0))
+            {
+                param = new ParametersWithIV(param, rc5Param.getIV());
+                ivParam = (ParametersWithIV)param;
+            }
+        }
+        else
+        {
+            throw new InvalidAlgorithmParameterException("unknown parameter type.");
+        }
+
+        if ((ivLength != 0) && !(param instanceof ParametersWithIV))
+        {
+            if (random == null)
+            {
+                random = new SecureRandom();
+            }
+
+            if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE))
+            {
+                byte[]  iv = new byte[ivLength];
+
+                random.nextBytes(iv);
+                param = new ParametersWithIV(param, iv);
+                ivParam = (ParametersWithIV)param;
+            }
+            else
+            {
+                throw new InvalidAlgorithmParameterException("no IV set when one expected");
+            }
+        }
+
+        switch (opmode)
+        {
+        case Cipher.ENCRYPT_MODE:
+        case Cipher.WRAP_MODE:
+            cipher.init(true, param);
+            break;
+        case Cipher.DECRYPT_MODE:
+        case Cipher.UNWRAP_MODE:
+            cipher.init(false, param);
+            break;
+        default:
+            System.out.println("eeek!");
+        }
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key                 key,
+        AlgorithmParameters params,
+        SecureRandom        random) 
+    throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        AlgorithmParameterSpec  paramSpec = null;
+
+        if (params != null)
+        {
+            for (int i = 0; i != availableSpecs.length; i++)
+            {
+                try
+                {
+                    paramSpec = params.getParameterSpec(availableSpecs[i]);
+                    break;
+                }
+                catch (Exception e)
+                {
+                    continue;
+                }
+            }
+
+            if (paramSpec == null)
+            {
+                throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString());
+            }
+        }
+
+        engineParams = params;
+        engineInit(opmode, key, paramSpec, random);
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key                 key,
+        SecureRandom        random) 
+        throws InvalidKeyException
+    {
+        try
+        {
+            engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+        }
+        catch (InvalidAlgorithmParameterException e)
+        {
+            throw new IllegalArgumentException(e.getMessage());
+        }
+    }
+
+    protected byte[] engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen) 
+    {
+        int     length = cipher.getUpdateOutputSize(inputLen);
+
+        if (length > 0)
+        {
+                byte[]  out = new byte[length];
+
+                cipher.processBytes(input, inputOffset, inputLen, out, 0);
+                return out;
+        }
+
+        cipher.processBytes(input, inputOffset, inputLen, null, 0);
+
+        return null;
+    }
+
+    protected int engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset) 
+    {
+        return cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+    }
+
+    protected byte[] engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen) 
+        throws IllegalBlockSizeException, BadPaddingException
+    {
+        int     len = 0;
+        byte[]  tmp = new byte[engineGetOutputSize(inputLen)];
+
+        if (inputLen != 0)
+        {
+            len = cipher.processBytes(input, inputOffset, inputLen, tmp, 0);
+        }
+
+        try
+        {
+            len += cipher.doFinal(tmp, len);
+        }
+        catch (DataLengthException e)
+        {
+            throw new IllegalBlockSizeException(e.getMessage());
+        }
+        catch (InvalidCipherTextException e)
+        {
+            throw new BadPaddingException(e.getMessage());
+        }
+
+        byte[]  out = new byte[len];
+
+        System.arraycopy(tmp, 0, out, 0, len);
+
+        return out;
+    }
+
+    protected int engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset) 
+        throws IllegalBlockSizeException, BadPaddingException
+    {
+        int     len = 0;
+
+        if (inputLen != 0)
+        {
+                len = cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+        }
+
+        try
+        {
+            return len + cipher.doFinal(output, outputOffset + len);
+        }
+        catch (DataLengthException e)
+        {
+            throw new IllegalBlockSizeException(e.getMessage());
+        }
+        catch (InvalidCipherTextException e)
+        {
+            throw new BadPaddingException(e.getMessage());
+        }
+    }
+
+    protected byte[] engineWrap(
+        Key     key) 
+    throws IllegalBlockSizeException, java.security.InvalidKeyException
+    {
+        byte[] encoded = key.getEncoded();
+        if (encoded == null)
+        {
+            throw new InvalidKeyException("Cannot wrap key, null encoding.");
+        }
+
+        try
+        {
+            return engineDoFinal(encoded, 0, encoded.length);
+        }
+        catch (BadPaddingException e)
+        {
+            throw new IllegalBlockSizeException(e.getMessage());
+        }
+    }
+
+    protected Key engineUnwrap(
+        byte[]  wrappedKey,
+        String  wrappedKeyAlgorithm,
+        int     wrappedKeyType) 
+    throws InvalidKeyException
+    {
+        byte[] encoded = null;
+        try
+        {
+            encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
+        }
+        catch (BadPaddingException e)
+        {
+            throw new InvalidKeyException(e.getMessage());
+        }
+        catch (IllegalBlockSizeException e2)
+        {
+            throw new InvalidKeyException(e2.getMessage());
+        }
+
+        if (wrappedKeyType == Cipher.SECRET_KEY)
+        {
+            return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
+        }
+        else
+        {
+            try
+            {
+                KeyFactory kf = KeyFactory.getInstance(wrappedKeyAlgorithm, "BC");
+
+                if (wrappedKeyType == Cipher.PUBLIC_KEY)
+                {
+                    return kf.generatePublic(new X509EncodedKeySpec(encoded));
+                }
+                else if (wrappedKeyType == Cipher.PRIVATE_KEY)
+                {
+                    return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
+                }
+            }
+            catch (NoSuchProviderException e)
+            {
+                throw new InvalidKeyException("Unknown key type " + e.getMessage());
+            }
+            catch (NoSuchAlgorithmException e)
+            {
+                throw new InvalidKeyException("Unknown key type " + e.getMessage());
+            }
+            catch (InvalidKeySpecException e2)
+            {
+                throw new InvalidKeyException("Unknown key type " + e2.getMessage());
+            }
+
+            throw new InvalidKeyException("Unknown key type " + wrappedKeyType);
+        }
+    }
+
+    /*
+     * The ciphers that inherit from us.
+     */
+
+    /**
+     * PBEWithMD5AndDES
+     */
+    static public class BrokePBEWithMD5AndDES
+        extends BrokenJCEBlockCipher
+    {
+        public BrokePBEWithMD5AndDES()
+        {
+            super(new CBCBlockCipher(new DESEngine()), PKCS5S1, MD5, 64, 64);
+        }
+    }
+
+    /**
+     * PBEWithSHA1AndDES
+     */
+    static public class BrokePBEWithSHA1AndDES
+        extends BrokenJCEBlockCipher
+    {
+        public BrokePBEWithSHA1AndDES()
+        {
+            super(new CBCBlockCipher(new DESEngine()), PKCS5S1, SHA1, 64, 64);
+        }
+    }
+
+    /**
+     * PBEWithSHAAnd3-KeyTripleDES-CBC
+     */
+    static public class BrokePBEWithSHAAndDES3Key
+        extends BrokenJCEBlockCipher
+    {
+        public BrokePBEWithSHAAndDES3Key()
+        {
+            super(new CBCBlockCipher(new DESedeEngine()), PKCS12, SHA1, 192, 64);
+        }
+    }
+
+    /**
+     * OldPBEWithSHAAnd3-KeyTripleDES-CBC
+     */
+    static public class OldPBEWithSHAAndDES3Key
+        extends BrokenJCEBlockCipher
+    {
+        public OldPBEWithSHAAndDES3Key()
+        {
+            super(new CBCBlockCipher(new DESedeEngine()), OLD_PKCS12, SHA1, 192, 64);
+        }
+    }
+
+    /**
+     * PBEWithSHAAnd2-KeyTripleDES-CBC
+     */
+    static public class BrokePBEWithSHAAndDES2Key
+        extends BrokenJCEBlockCipher
+    {
+        public BrokePBEWithSHAAndDES2Key()
+        {
+            super(new CBCBlockCipher(new DESedeEngine()), PKCS12, SHA1, 128, 64);
+        }
+    }
+
+    /**
+     * OldPBEWithSHAAndTwofish-CBC
+     */
+// BEGIN android-removed
+//    static public class OldPBEWithSHAAndTwofish
+//        extends BrokenJCEBlockCipher
+//    {
+//        public OldPBEWithSHAAndTwofish()
+//        {
+//            super(new CBCBlockCipher(new TwofishEngine()), OLD_PKCS12, SHA1, 256, 128);
+//        }
+//    }
+// END android-removed
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/BrokenKDF2BytesGenerator.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/BrokenKDF2BytesGenerator.java
new file mode 100644
index 0000000..e6186f6
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/BrokenKDF2BytesGenerator.java
@@ -0,0 +1,127 @@
+package org.bouncycastle.jce.provider;
+
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.DerivationFunction;
+import org.bouncycastle.crypto.DerivationParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.params.KDFParameters;
+
+/**
+ * Generator for PBE derived keys and ivs as defined by IEEE P1363a
+ * <br>
+ * This implementation is based on draft 9 of IEEE P1363a. <b>Note:</b>
+ * as this is still a draft the output of this generator may change, don't
+ * use it for anything that might be subject to long term storage.
+ */
+public class BrokenKDF2BytesGenerator
+    implements DerivationFunction
+{
+    private Digest  digest;
+    private byte[]  shared;
+    private byte[]  iv;
+
+    /**
+     * Construct a KDF2 Parameters generator. Generates key material
+     * according to IEEE P1363a - if you want orthodox results you should
+     * use a digest specified in the standard.
+     * <p>
+     * <b>Note:</b> IEEE P1363a standard is still a draft standard, if the standard
+     * changes this function, the output of this function will change as well.
+     * Don't use this routine for anything subject to long term storage.
+     *
+     * @param digest the digest to be used as the source of derived keys.
+     */
+    public BrokenKDF2BytesGenerator(
+        Digest  digest)
+    {
+        this.digest = digest;
+    }
+
+    public void init(
+        DerivationParameters    param)
+    {
+        if (!(param instanceof KDFParameters))
+        {
+            throw new IllegalArgumentException("KDF parameters required for KDF2Generator");
+        }
+
+        KDFParameters   p = (KDFParameters)param;
+
+        shared = p.getSharedSecret();
+        iv = p.getIV();
+    }
+
+    /**
+     * return the underlying digest.
+     */
+    public Digest getDigest()
+    {
+        return digest;
+    }
+
+    /**
+     * fill len bytes of the output buffer with bytes generated from
+     * the derivation function.
+     *
+     * @throws IllegalArgumentException if the size of the request will cause an overflow.
+     * @throws DataLengthException if the out buffer is too small.
+     */
+    public int generateBytes(
+        byte[]  out,
+        int     outOff,
+        int     len)
+        throws DataLengthException, IllegalArgumentException
+    {
+        if ((out.length - len) < outOff)
+        {
+            throw new DataLengthException("output buffer too small");
+        }
+
+        long    oBits = len * 8;
+
+        //
+        // this is at odds with the standard implementation, the
+        // maximum value should be hBits * (2^23 - 1) where hBits
+        // is the digest output size in bits. We can't have an
+        // array with a long index at the moment...
+        //
+        if (oBits > (digest.getDigestSize() * 8 * (2L^32 - 1)))
+        {
+            new IllegalArgumentException("Output length to large");
+        }
+    
+        int cThreshold = (int)(oBits / digest.getDigestSize());
+
+        byte[] dig = null;
+
+        dig = new byte[digest.getDigestSize()];
+
+        for (int counter = 1; counter <= cThreshold; counter++)
+        {
+            digest.update(shared, 0, shared.length);
+
+            digest.update((byte)(counter & 0xff));
+            digest.update((byte)((counter >> 8) & 0xff));
+            digest.update((byte)((counter >> 16) & 0xff));
+            digest.update((byte)((counter >> 24) & 0xff));
+
+            digest.update(iv, 0, iv.length);
+
+            digest.doFinal(dig, 0);
+
+            if ((len - outOff) > dig.length)
+            {
+                System.arraycopy(dig, 0, out, outOff, dig.length);
+                outOff += dig.length;
+            }
+            else
+            {
+                System.arraycopy(dig, 0, out, outOff, len - outOff);
+            }
+        }
+    
+        digest.reset();
+
+        return len;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/BrokenPBE.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/BrokenPBE.java
new file mode 100644
index 0000000..6ac4f49
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/BrokenPBE.java
@@ -0,0 +1,448 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.PBEParametersGenerator;
+import org.bouncycastle.crypto.digests.MD5Digest;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
+// END android-removed
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;
+import org.bouncycastle.crypto.generators.PKCS5S1ParametersGenerator;
+import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * Generator for PBE derived keys and ivs as defined by PKCS 12 V1.0,
+ * with a bug affecting 180 bit plus keys - this class is only here to
+ * allow smooth migration of the version 0 keystore to version 1. Don't
+ * use it (it won't be staying around).
+ * <p>
+ * The document this implementation is based on can be found at
+ * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-12/index.html>
+ * RSA's PKCS12 Page</a>
+ */
+class OldPKCS12ParametersGenerator
+    extends PBEParametersGenerator
+{
+    public static final int KEY_MATERIAL = 1;
+    public static final int IV_MATERIAL  = 2;
+    public static final int MAC_MATERIAL = 3;
+
+    private Digest digest;
+
+    private int     u;
+    private int     v;
+
+    /**
+     * Construct a PKCS 12 Parameters generator. This constructor will
+     * accept MD5, SHA1, and RIPEMD160.
+     *
+     * @param digest the digest to be used as the source of derived keys.
+     * @exception IllegalArgumentException if an unknown digest is passed in.
+     */
+    public OldPKCS12ParametersGenerator(
+        Digest  digest)
+    {
+        this.digest = digest;
+        if (digest instanceof MD5Digest)
+        {
+            u = 128 / 8;
+            v = 512 / 8;
+        }
+        else if (digest instanceof SHA1Digest)
+        {
+            u = 160 / 8;
+            v = 512 / 8;
+        }
+        // BEGIN android-removed
+        // else if (digest instanceof RIPEMD160Digest)
+        // {
+        //     u = 160 / 8;
+        //     v = 512 / 8;
+        // }
+        // END android-removed
+        else
+        {
+            throw new IllegalArgumentException("Digest " + digest.getAlgorithmName() + " unsupported");
+        }
+    }
+
+    /**
+     * add a + b + 1, returning the result in a. The a value is treated
+     * as a BigInteger of length (b.length * 8) bits. The result is 
+     * modulo 2^b.length in case of overflow.
+     */
+    private void adjust(
+        byte[]  a,
+        int     aOff,
+        byte[]  b)
+    {
+        int  x = (b[b.length - 1] & 0xff) + (a[aOff + b.length - 1] & 0xff) + 1;
+
+        a[aOff + b.length - 1] = (byte)x;
+        x >>>= 8;
+
+        for (int i = b.length - 2; i >= 0; i--)
+        {
+            x += (b[i] & 0xff) + (a[aOff + i] & 0xff);
+            a[aOff + i] = (byte)x;
+            x >>>= 8;
+        }
+    }
+
+    /**
+     * generation of a derived key ala PKCS12 V1.0.
+     */
+    private byte[] generateDerivedKey(
+        int idByte,
+        int n)
+    {
+        byte[]  D = new byte[v];
+        byte[]  dKey = new byte[n];
+
+        for (int i = 0; i != D.length; i++)
+        {
+            D[i] = (byte)idByte;
+        }
+
+        byte[]  S;
+
+        if ((salt != null) && (salt.length != 0))
+        {
+            S = new byte[v * ((salt.length + v - 1) / v)];
+
+            for (int i = 0; i != S.length; i++)
+            {
+                S[i] = salt[i % salt.length];
+            }
+        }
+        else
+        {
+            S = new byte[0];
+        }
+
+        byte[]  P;
+
+        if ((password != null) && (password.length != 0))
+        {
+            P = new byte[v * ((password.length + v - 1) / v)];
+
+            for (int i = 0; i != P.length; i++)
+            {
+                P[i] = password[i % password.length];
+            }
+        }
+        else
+        {
+            P = new byte[0];
+        }
+
+        byte[]  I = new byte[S.length + P.length];
+
+        System.arraycopy(S, 0, I, 0, S.length);
+        System.arraycopy(P, 0, I, S.length, P.length);
+
+        byte[]  B = new byte[v];
+        int     c = (n + u - 1) / u;
+
+        for (int i = 1; i <= c; i++)
+        {
+            byte[]  A = new byte[u];
+
+            digest.update(D, 0, D.length);
+            digest.update(I, 0, I.length);
+            digest.doFinal(A, 0);
+            for (int j = 1; j != iterationCount; j++)
+            {
+                digest.update(A, 0, A.length);
+                digest.doFinal(A, 0);
+            }
+
+            for (int j = 0; j != B.length; j++)
+            {
+                B[i] = A[j % A.length];
+            }
+
+            for (int j = 0; j != I.length / v; j++)
+            {
+                adjust(I, j * v, B);
+            }
+
+            if (i == c)
+            {
+                System.arraycopy(A, 0, dKey, (i - 1) * u, dKey.length - ((i - 1) * u));
+            }
+            else
+            {
+                System.arraycopy(A, 0, dKey, (i - 1) * u, A.length);
+            }
+        }
+
+        return dKey;
+    }
+
+    /**
+     * Generate a key parameter derived from the password, salt, and iteration
+     * count we are currently initialised with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @return a KeyParameter object.
+     */
+    public CipherParameters generateDerivedParameters(
+        int keySize)
+    {
+        keySize = keySize / 8;
+
+        byte[]  dKey = generateDerivedKey(KEY_MATERIAL, keySize);
+
+        return new KeyParameter(dKey, 0, keySize);
+    }
+
+    /**
+     * Generate a key with initialisation vector parameter derived from
+     * the password, salt, and iteration count we are currently initialised
+     * with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @param ivSize the size of the iv we want (in bits)
+     * @return a ParametersWithIV object.
+     */
+    public CipherParameters generateDerivedParameters(
+        int     keySize,
+        int     ivSize)
+    {
+        keySize = keySize / 8;
+        ivSize = ivSize / 8;
+
+        byte[]  dKey = generateDerivedKey(KEY_MATERIAL, keySize);
+
+        byte[]  iv = generateDerivedKey(IV_MATERIAL, ivSize);
+
+        return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), iv, 0, ivSize);
+    }
+
+    /**
+     * Generate a key parameter for use with a MAC derived from the password,
+     * salt, and iteration count we are currently initialised with.
+     *
+     * @param keySize the size of the key we want (in bits)
+     * @return a KeyParameter object.
+     */
+    public CipherParameters generateDerivedMacParameters(
+        int keySize)
+    {
+        keySize = keySize / 8;
+
+        byte[]  dKey = generateDerivedKey(MAC_MATERIAL, keySize);
+
+        return new KeyParameter(dKey, 0, keySize);
+    }
+}
+
+public interface BrokenPBE
+{
+    //
+    // PBE Based encryption constants - by default we do PKCS12 with SHA-1
+    //
+    static final int        MD5         = 0;
+    static final int        SHA1        = 1;
+    static final int        RIPEMD160   = 2;
+
+    static final int        PKCS5S1     = 0;
+    static final int        PKCS5S2     = 1;
+    static final int        PKCS12      = 2;
+    static final int        OLD_PKCS12  = 3;
+
+    /**
+     * uses the appropriate mixer to generate the key and IV if neccessary.
+     */
+    static class Util
+    {
+        /**
+         * a faulty parity routine...
+         *
+         * @param bytes the byte array to set the parity on.
+         */
+        static private void setOddParity(
+            byte[] bytes)
+        {
+            for (int i = 0; i < bytes.length; i++)
+            {
+                int b = bytes[i];
+                bytes[i] = (byte)((b & 0xfe) |
+                                (((b >> 1) ^
+                                (b >> 2) ^
+                                (b >> 3) ^
+                                (b >> 4) ^
+                                (b >> 5) ^
+                                (b >> 6) ^
+                                (b >> 7)) ^ 0x01));
+            }
+        }
+
+        static private PBEParametersGenerator makePBEGenerator(
+            int                     type,
+            int                     hash)
+        {
+            PBEParametersGenerator  generator;
+    
+            if (type == PKCS5S1)
+            {
+                switch (hash)
+                {
+                case MD5:
+                    generator = new PKCS5S1ParametersGenerator(new MD5Digest());
+                    break;
+                case SHA1:
+                    generator = new PKCS5S1ParametersGenerator(new SHA1Digest());
+                    break;
+                default:
+                    throw new IllegalStateException("PKCS5 scheme 1 only supports only MD5 and SHA1.");
+                }
+            }
+            else if (type == PKCS5S2)
+            {
+                generator = new PKCS5S2ParametersGenerator();
+            }
+            else if (type == OLD_PKCS12)
+            {
+                switch (hash)
+                {
+                case MD5:
+                    generator = new OldPKCS12ParametersGenerator(new MD5Digest());
+                    break;
+                case SHA1:
+                    generator = new OldPKCS12ParametersGenerator(new SHA1Digest());
+                    break;
+                // BEGIN android-removed
+                // case RIPEMD160:
+                //     generator = new OldPKCS12ParametersGenerator(new RIPEMD160Digest());
+                //     break;
+                // END android-removed
+                default:
+                    throw new IllegalStateException("unknown digest scheme for PBE encryption.");
+                }
+            }
+            else
+            {
+                switch (hash)
+                {
+                case MD5:
+                    generator = new PKCS12ParametersGenerator(new MD5Digest());
+                    break;
+                case SHA1:
+                    generator = new PKCS12ParametersGenerator(new SHA1Digest());
+                    break;
+                // BEGIN android-removed
+                // case RIPEMD160:
+                //     generator = new PKCS12ParametersGenerator(new RIPEMD160Digest());
+                //     break;
+                // END android-removed
+                default:
+                    throw new IllegalStateException("unknown digest scheme for PBE encryption.");
+                }
+            }
+    
+            return generator;
+        }
+
+        /**
+         * construct a key and iv (if neccessary) suitable for use with a 
+         * Cipher.
+         */
+        static CipherParameters makePBEParameters(
+            JCEPBEKey               pbeKey,
+            AlgorithmParameterSpec  spec,
+            int                     type,
+            int                     hash,
+            String                  targetAlgorithm,
+            int                     keySize,
+            int                     ivSize)
+        {
+            if ((spec == null) || !(spec instanceof PBEParameterSpec))
+            {
+                throw new IllegalArgumentException("Need a PBEParameter spec with a PBE key.");
+            }
+    
+            PBEParameterSpec        pbeParam = (PBEParameterSpec)spec;
+            PBEParametersGenerator  generator = makePBEGenerator(type, hash);
+            byte[]                  key = pbeKey.getEncoded();
+            CipherParameters        param;
+    
+            generator.init(key, pbeParam.getSalt(), pbeParam.getIterationCount());
+
+            if (ivSize != 0)
+            {
+                param = generator.generateDerivedParameters(keySize, ivSize);
+            }
+            else
+            {
+                param = generator.generateDerivedParameters(keySize);
+            }
+
+            if (targetAlgorithm.startsWith("DES"))
+            {
+                if (param instanceof ParametersWithIV)
+                {
+                    KeyParameter    kParam = (KeyParameter)((ParametersWithIV)param).getParameters();
+
+                    setOddParity(kParam.getKey());
+                }
+                else
+                {
+                    KeyParameter    kParam = (KeyParameter)param;
+
+                    setOddParity(kParam.getKey());
+                }
+            }
+
+            for (int i = 0; i != key.length; i++)
+            {
+                key[i] = 0;
+            }
+
+            return param;
+        }
+
+        /**
+         * generate a PBE based key suitable for a MAC algorithm, the
+         * key size is chosen according the MAC size, or the hashing algorithm,
+         * whichever is greater.
+         */
+        static CipherParameters makePBEMacParameters(
+            JCEPBEKey               pbeKey,
+            AlgorithmParameterSpec  spec,
+            int                     type,
+            int                     hash,
+            int                     keySize)
+        {
+            if ((spec == null) || !(spec instanceof PBEParameterSpec))
+            {
+                throw new IllegalArgumentException("Need a PBEParameter spec with a PBE key.");
+            }
+    
+            PBEParameterSpec        pbeParam = (PBEParameterSpec)spec;
+            PBEParametersGenerator  generator = makePBEGenerator(type, hash);
+            byte[]                  key = pbeKey.getEncoded();
+            CipherParameters        param;
+    
+            generator.init(key, pbeParam.getSalt(), pbeParam.getIterationCount());
+
+            param = generator.generateDerivedMacParameters(keySize);
+    
+            for (int i = 0; i != key.length; i++)
+            {
+                key[i] = 0;
+            }
+
+            return param;
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
new file mode 100644
index 0000000..aca61a7
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
@@ -0,0 +1,857 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.PublicKey;
+import java.security.cert.CRL;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertSelector;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
+import java.security.cert.PKIXParameters;
+import java.security.cert.PolicyQualifierInfo;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLSelector;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1OutputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.PolicyInformation;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x509.X509Extensions;
+
+public class CertPathValidatorUtilities
+{
+
+    protected static final String CERTIFICATE_POLICIES = X509Extensions.CertificatePolicies.getId();
+    protected static final String BASIC_CONSTRAINTS = X509Extensions.BasicConstraints.getId();
+    protected static final String POLICY_MAPPINGS = X509Extensions.PolicyMappings.getId();
+    protected static final String SUBJECT_ALTERNATIVE_NAME = X509Extensions.SubjectAlternativeName.getId();
+    protected static final String NAME_CONSTRAINTS = X509Extensions.NameConstraints.getId();
+    protected static final String KEY_USAGE = X509Extensions.KeyUsage.getId();
+    protected static final String INHIBIT_ANY_POLICY = X509Extensions.InhibitAnyPolicy.getId();
+    protected static final String ISSUING_DISTRIBUTION_POINT = X509Extensions.IssuingDistributionPoint.getId();
+    protected static final String DELTA_CRL_INDICATOR = X509Extensions.DeltaCRLIndicator.getId();
+    protected static final String POLICY_CONSTRAINTS = X509Extensions.PolicyConstraints.getId();
+    
+
+    protected static final String ANY_POLICY = "2.5.29.32.0";
+    
+    protected static final String CRL_NUMBER = X509Extensions.CRLNumber.getId();
+    
+    /*
+     * key usage bits
+     */
+    protected static final int    KEY_CERT_SIGN = 5;
+    protected static final int    CRL_SIGN = 6;
+
+    protected static final String[] crlReasons = new String[] {
+        "unspecified",
+        "keyCompromise",
+        "cACompromise",
+        "affiliationChanged",
+        "superseded",
+        "cessationOfOperation",
+        "certificateHold",
+        "unknown",
+        "removeFromCRL",
+        "privilegeWithdrawn",
+        "aACompromise" };
+    
+    /**
+     * Search the given Set of TrustAnchor's for one that is the
+     * issuer of the given X509 certificate.
+     *
+     * @param cert the X509 certificate
+     * @param trustAnchors a Set of TrustAnchor's
+     *
+     * @return the <code>TrustAnchor</code> object if found or
+     * <code>null</code> if not.
+     *
+     * @exception CertPathValidatorException if a TrustAnchor  was
+     * found but the signature verification on the given certificate
+     * has thrown an exception. This Exception can be obtainted with
+     * <code>getCause()</code> method.
+     **/
+    protected static final TrustAnchor findTrustAnchor(
+        X509Certificate cert,
+        CertPath        certPath,
+        int             index,
+        Set             trustAnchors) 
+        throws CertPathValidatorException
+    {
+        Iterator iter = trustAnchors.iterator();
+        TrustAnchor trust = null;
+        PublicKey trustPublicKey = null;
+        Exception invalidKeyEx = null;
+
+        X509CertSelector certSelectX509 = new X509CertSelector();
+
+        try
+        {
+            certSelectX509.setSubject(getEncodedIssuerPrincipal(cert).getEncoded());
+        }
+        catch (IOException ex)
+        {
+            throw new CertPathValidatorException(ex);
+        }
+
+        while (iter.hasNext() && trust == null)
+        {
+            trust = (TrustAnchor) iter.next();
+            if (trust.getTrustedCert() != null)
+            {
+                if (certSelectX509.match(trust.getTrustedCert()))
+                {
+                    trustPublicKey = trust.getTrustedCert().getPublicKey();
+                }
+                else
+                {
+                    trust = null;
+                }
+            }
+            else if (trust.getCAName() != null
+                    && trust.getCAPublicKey() != null)
+            {
+                try
+                {
+                    X500Principal certIssuer = getEncodedIssuerPrincipal(cert);
+                    X500Principal caName = new X500Principal(trust.getCAName());
+                    if (certIssuer.equals(caName))
+                    {
+                        trustPublicKey = trust.getCAPublicKey();
+                    }
+                    else
+                    {
+                        trust = null;
+                    }
+                }
+                catch (IllegalArgumentException ex)
+                {
+                    trust = null;
+                }
+            }
+            else
+            {
+                trust = null;
+            }
+
+            if (trustPublicKey != null)
+            {
+                try
+                {
+                    cert.verify(trustPublicKey);
+                }
+                catch (Exception ex)
+                {
+                    invalidKeyEx = ex;
+                    trust = null;
+                }
+            }
+        }
+
+        if (trust == null && invalidKeyEx != null)
+        {
+            throw new CertPathValidatorException("TrustAnchor found but certificate validation failed.", invalidKeyEx, certPath, index);
+        }
+
+        return trust;
+    }
+
+    protected static X500Principal getEncodedIssuerPrincipal(X509Certificate cert)
+    {
+        return cert.getIssuerX500Principal();
+    }
+
+    protected static Date getValidDate(PKIXParameters paramsPKIX)
+    {
+        Date validDate = paramsPKIX.getDate();
+
+        if (validDate == null)
+        {
+            validDate = new Date();
+        }
+
+        return validDate;
+    }
+
+    protected static X500Principal getSubjectPrincipal(X509Certificate cert)
+    {
+        return cert.getSubjectX500Principal();
+    }
+    
+    protected static boolean isSelfIssued(X509Certificate cert)
+    {
+        return cert.getSubjectDN().equals(cert.getIssuerDN());
+    }
+    
+    
+    /**
+     * extract the value of the given extension, if it exists.
+     */
+    protected static DERObject getExtensionValue(
+        java.security.cert.X509Extension    ext,
+        String                              oid)
+        throws AnnotatedException
+    {
+        byte[]  bytes = ext.getExtensionValue(oid);
+        if (bytes == null)
+        {
+            return null;
+        }
+
+        return getObject(oid, bytes);
+    }
+    
+    private static DERObject getObject(
+            String oid,
+            byte[] ext)
+            throws AnnotatedException
+    {
+        try
+        {
+            ASN1InputStream aIn = new ASN1InputStream(ext);
+            ASN1OctetString octs = (ASN1OctetString)aIn.readObject();
+
+            aIn = new ASN1InputStream(octs.getOctets());
+            return aIn.readObject();
+        }
+        catch (IOException e)
+        {
+            throw new AnnotatedException("exception processing extension " + oid, e);
+        }
+    }
+    
+    protected static X500Principal getIssuerPrincipal(X509CRL crl)
+    {
+        return crl.getIssuerX500Principal();
+    }
+    
+    protected static AlgorithmIdentifier getAlgorithmIdentifier(
+        PublicKey key)
+        throws CertPathValidatorException
+    {
+        try
+        {
+            ASN1InputStream      aIn = new ASN1InputStream(key.getEncoded());
+
+            SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(aIn.readObject());
+
+            return info.getAlgorithmId();
+        }
+        catch (IOException e)
+        {
+            throw new CertPathValidatorException("exception processing public key");
+        }
+    }
+
+    //
+    // Utility functions for name constraint checking
+    //
+
+    private static boolean withinDNSubtree(ASN1Sequence dns, ASN1Sequence subtree)
+    {
+        if (subtree.size() < 1)
+        {
+            return false;
+        }
+
+        if (subtree.size() > dns.size())
+        {
+            return false;
+        }
+
+        for (int j = subtree.size() - 1; j >= 0; j--)
+        {
+            if (!subtree.getObjectAt(j).equals(dns.getObjectAt(j)))
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    protected static void checkPermittedDN(Set permitted, ASN1Sequence dns)
+            throws CertPathValidatorException
+    {
+        if (permitted.isEmpty())
+        {
+            return;
+        }
+
+        Iterator it = permitted.iterator();
+
+        while (it.hasNext())
+        {
+            ASN1Sequence subtree = (ASN1Sequence) it.next();
+
+            if (withinDNSubtree(dns, subtree))
+            {
+                return;
+            }
+        }
+
+        throw new CertPathValidatorException(
+                "Subject distinguished name is not from a permitted subtree");
+    }
+
+    protected static void checkExcludedDN(Set excluded, ASN1Sequence dns)
+            throws CertPathValidatorException
+    {
+        if (excluded.isEmpty())
+        {
+            return;
+        }
+
+        Iterator it = excluded.iterator();
+
+        while (it.hasNext())
+        {
+            ASN1Sequence subtree = (ASN1Sequence) it.next();
+
+            if (withinDNSubtree(dns, subtree))
+            {
+                throw new CertPathValidatorException(
+                        "Subject distinguished name is from an excluded subtree");
+            }
+        }
+    }
+
+    protected static Set intersectDN(Set permitted, ASN1Sequence dn)
+    {
+        if (permitted.isEmpty())
+        {
+            permitted.add(dn);
+
+            return permitted;
+        }
+        else
+        {
+            Set intersect = new HashSet();
+
+            Iterator _iter = permitted.iterator();
+            while (_iter.hasNext())
+            {
+                ASN1Sequence subtree = (ASN1Sequence) _iter.next();
+
+                if (withinDNSubtree(dn, subtree))
+                {
+                    intersect.add(dn);
+                }
+                else if (withinDNSubtree(subtree, dn))
+                {
+                    intersect.add(subtree);
+                }
+            }
+
+            return intersect;
+        }
+    }
+
+    protected static Set unionDN(Set excluded, ASN1Sequence dn)
+    {
+        if (excluded.isEmpty())
+        {
+            excluded.add(dn);
+
+            return excluded;
+        }
+        else
+        {
+            Set intersect = new HashSet();
+
+            Iterator _iter = excluded.iterator();
+            while (_iter.hasNext())
+            {
+                ASN1Sequence subtree = (ASN1Sequence) _iter.next();
+
+                if (withinDNSubtree(dn, subtree))
+                {
+                    intersect.add(subtree);
+                }
+                else if (withinDNSubtree(subtree, dn))
+                {
+                    intersect.add(dn);
+                }
+                else
+                {
+                    intersect.add(subtree);
+                    intersect.add(dn);
+                }
+            }
+
+            return intersect;
+        }
+    }
+
+    protected static Set intersectEmail(Set permitted, String email)
+    {
+        String _sub = email.substring(email.indexOf('@') + 1);
+
+        if (permitted.isEmpty())
+        {
+            permitted.add(_sub);
+
+            return permitted;
+        }
+        else
+        {
+            Set intersect = new HashSet();
+
+            Iterator _iter = permitted.iterator();
+            while (_iter.hasNext())
+            {
+                String _permitted = (String) _iter.next();
+
+                if (_sub.endsWith(_permitted))
+                {
+                    intersect.add(_sub);
+                }
+                else if (_permitted.endsWith(_sub))
+                {
+                    intersect.add(_permitted);
+                }
+            }
+
+            return intersect;
+        }
+    }
+
+    protected static Set unionEmail(Set excluded, String email)
+    {
+        String _sub = email.substring(email.indexOf('@') + 1);
+
+        if (excluded.isEmpty())
+        {
+            excluded.add(_sub);
+            return excluded;
+        }
+        else
+        {
+            Set intersect = new HashSet();
+
+            Iterator _iter = excluded.iterator();
+            while (_iter.hasNext())
+            {
+                String _excluded = (String) _iter.next();
+
+                if (_sub.endsWith(_excluded))
+                {
+                    intersect.add(_excluded);
+                }
+                else if (_excluded.endsWith(_sub))
+                {
+                    intersect.add(_sub);
+                }
+                else
+                {
+                    intersect.add(_excluded);
+                    intersect.add(_sub);
+                }
+            }
+
+            return intersect;
+        }
+    }
+
+    protected static Set intersectIP(Set permitted, byte[] ip)
+    {
+        // TBD
+        return permitted;
+    }
+
+    protected static Set unionIP(Set excluded, byte[] ip)
+    {
+        // TBD
+        return excluded;
+    }
+
+    protected static void checkPermittedEmail(Set permitted, String email)
+            throws CertPathValidatorException
+    {
+        if (permitted.isEmpty())
+        {
+            return;
+        }
+
+        String sub = email.substring(email.indexOf('@') + 1);
+        Iterator it = permitted.iterator();
+
+        while (it.hasNext())
+        {
+            String str = (String) it.next();
+
+            if (sub.endsWith(str))
+            {
+                return;
+            }
+        }
+
+        throw new CertPathValidatorException(
+                "Subject email address is not from a permitted subtree");
+    }
+
+    protected static void checkExcludedEmail(Set excluded, String email)
+            throws CertPathValidatorException
+    {
+        if (excluded.isEmpty())
+        {
+            return;
+        }
+
+        String sub = email.substring(email.indexOf('@') + 1);
+        Iterator it = excluded.iterator();
+
+        while (it.hasNext())
+        {
+            String str = (String) it.next();
+            if (sub.endsWith(str))
+            {
+                throw new CertPathValidatorException(
+                        "Subject email address is from an excluded subtree");
+            }
+        }
+    }
+
+    protected static void checkPermittedIP(Set permitted, byte[] ip)
+            throws CertPathValidatorException
+    {
+        if (permitted.isEmpty())
+        {
+            return;
+        }
+
+        // TODO: ??? Something here
+    }
+
+    protected static void checkExcludedIP(Set excluded, byte[] ip)
+            throws CertPathValidatorException
+    {
+        if (excluded.isEmpty())
+        {
+            return;
+        }
+
+        // TODO, check RFC791 and RFC1883 for IP bytes definition.
+    }
+    
+    
+    // crl checking
+    
+    /**
+     * Return a Collection of all CRLs found in the
+     * CertStore's that are matching the crlSelect criteriums.
+     *
+     * @param crlSelect a {@link CertSelector CertSelector}
+     * object that will be used to select the CRLs
+     * @param crlStores a List containing only {@link CertStore
+     * CertStore} objects. These are used to search for
+     * CRLs
+     *
+     * @return a Collection of all found {@link CRL CRL}
+     * objects. May be empty but never <code>null</code>.
+     */
+    protected static final Collection findCRLs(
+        X509CRLSelector crlSelect,
+        List            crlStores)
+        throws AnnotatedException
+    {
+        Set crls = new HashSet();
+        Iterator iter = crlStores.iterator();
+    
+        while (iter.hasNext())
+        {
+            CertStore   certStore = (CertStore)iter.next();
+    
+            try
+            {
+                crls.addAll(certStore.getCRLs(crlSelect));
+            }
+            catch (CertStoreException e)
+            {
+                throw new AnnotatedException("cannot extract crl: " + e, e);
+            }
+        }
+    
+        return crls;
+    }
+    
+    //
+    // policy checking
+    // 
+    
+    protected static final Set getQualifierSet(ASN1Sequence qualifiers) 
+        throws CertPathValidatorException
+    {
+        Set             pq   = new HashSet();
+        
+        if (qualifiers == null)
+        {
+            return pq;
+        }
+        
+        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+        ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
+    
+        Enumeration e = qualifiers.getObjects();
+    
+        while (e.hasMoreElements())
+        {
+            try
+            {
+                aOut.writeObject(e.nextElement());
+    
+                pq.add(new PolicyQualifierInfo(bOut.toByteArray()));
+            }
+            catch (IOException ex)
+            {
+                throw new CertPathValidatorException("exception building qualifier set: " + ex);
+            }
+    
+            bOut.reset();
+        }
+        
+        return pq;
+    }
+    
+    protected static PKIXPolicyNode removePolicyNode(
+        PKIXPolicyNode  validPolicyTree,
+        List     []        policyNodes,
+        PKIXPolicyNode _node)
+    {
+        PKIXPolicyNode _parent = (PKIXPolicyNode)_node.getParent();
+        
+        if (validPolicyTree == null)
+        {
+            return null;
+        }
+
+        if (_parent == null)
+        {
+            for (int j = 0; j < policyNodes.length; j++)
+            {
+                policyNodes[j] = new ArrayList();
+            }
+
+            return null;
+        }
+        else
+        {
+            _parent.removeChild(_node);
+            removePolicyNodeRecurse(policyNodes, _node);
+
+            return validPolicyTree;
+        }
+    }
+    
+    private static void removePolicyNodeRecurse(
+        List     []        policyNodes,
+        PKIXPolicyNode  _node)
+    {
+        policyNodes[_node.getDepth()].remove(_node);
+
+        if (_node.hasChildren())
+        {
+            Iterator _iter = _node.getChildren();
+            while (_iter.hasNext())
+            {
+                PKIXPolicyNode _child = (PKIXPolicyNode)_iter.next();
+                removePolicyNodeRecurse(policyNodes, _child);
+            }
+        }
+    }
+    
+    
+    protected static boolean processCertD1i(
+        int                 index,
+        List     []            policyNodes,
+        DERObjectIdentifier pOid,
+        Set                 pq)
+    {
+        List       policyNodeVec = policyNodes[index - 1];
+
+        for (int j = 0; j < policyNodeVec.size(); j++)
+        {
+            PKIXPolicyNode node = (PKIXPolicyNode)policyNodeVec.get(j);
+            Set            expectedPolicies = node.getExpectedPolicies();
+            
+            if (expectedPolicies.contains(pOid.getId()))
+            {
+                Set childExpectedPolicies = new HashSet();
+                childExpectedPolicies.add(pOid.getId());
+                
+                PKIXPolicyNode child = new PKIXPolicyNode(new ArrayList(),
+                                                           index,
+                                                           childExpectedPolicies,
+                                                           node,
+                                                           pq,
+                                                           pOid.getId(),
+                                                           false);
+                node.addChild(child);
+                policyNodes[index].add(child);
+                
+                return true;
+            }
+        }
+        
+        return false;
+    }
+
+    protected static void processCertD1ii(
+        int                 index,
+        List     []            policyNodes,
+        DERObjectIdentifier _poid,
+        Set _pq)
+    {
+        List       policyNodeVec = policyNodes[index - 1];
+
+        for (int j = 0; j < policyNodeVec.size(); j++)
+        {
+            PKIXPolicyNode _node = (PKIXPolicyNode)policyNodeVec.get(j);
+            Set            _expectedPolicies = _node.getExpectedPolicies();
+            
+            if (ANY_POLICY.equals(_node.getValidPolicy()))
+            {
+                Set _childExpectedPolicies = new HashSet();
+                _childExpectedPolicies.add(_poid.getId());
+                
+                PKIXPolicyNode _child = new PKIXPolicyNode(new ArrayList(),
+                                                           index,
+                                                           _childExpectedPolicies,
+                                                           _node,
+                                                           _pq,
+                                                           _poid.getId(),
+                                                           false);
+                _node.addChild(_child);
+                policyNodes[index].add(_child);
+                return;
+            }
+        }
+    }
+    
+    protected static void prepareNextCertB1(
+            int i,
+            List[] policyNodes,
+            String id_p,
+            Map m_idp,
+            X509Certificate cert
+            ) throws AnnotatedException,CertPathValidatorException
+    {
+        boolean idp_found = false;
+        Iterator nodes_i = policyNodes[i].iterator();
+        while (nodes_i.hasNext())
+        {
+            PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+            if (node.getValidPolicy().equals(id_p))
+            {
+                idp_found = true;
+                node.expectedPolicies = (Set)m_idp.get(id_p);
+                break;
+            }
+        }
+
+        if (!idp_found)
+        {
+            nodes_i = policyNodes[i].iterator();
+            while (nodes_i.hasNext())
+            {
+                PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+                if (ANY_POLICY.equals(node.getValidPolicy()))
+                {
+                    Set pq = null;
+                    ASN1Sequence policies = (ASN1Sequence)getExtensionValue(cert, CERTIFICATE_POLICIES);
+                    Enumeration e = policies.getObjects();
+                    while (e.hasMoreElements())
+                    {
+                        PolicyInformation pinfo = PolicyInformation.getInstance(e.nextElement());
+                        if (ANY_POLICY.equals(pinfo.getPolicyIdentifier().getId()))
+                        {
+                            pq = getQualifierSet(pinfo.getPolicyQualifiers());
+                            break;
+                        }
+                    }
+                    boolean ci = false;
+                    if (cert.getCriticalExtensionOIDs() != null)
+                    {
+                        ci = cert.getCriticalExtensionOIDs().contains(CERTIFICATE_POLICIES);
+                    }
+
+                    PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+                    if (ANY_POLICY.equals(p_node.getValidPolicy()))
+                    {
+                        PKIXPolicyNode c_node = new PKIXPolicyNode(
+                                new ArrayList(), i,
+                                (Set)m_idp.get(id_p),
+                                p_node, pq, id_p, ci);
+                        p_node.addChild(c_node);
+                        policyNodes[i].add(c_node);
+                    }
+                    break;
+                }
+            }
+        }
+    }
+    
+    protected static PKIXPolicyNode prepareNextCertB2(
+            int i,
+            List[] policyNodes,
+            String id_p,
+            PKIXPolicyNode validPolicyTree) 
+    {
+        Iterator nodes_i = policyNodes[i].iterator();
+        while (nodes_i.hasNext())
+        {
+            PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+            if (node.getValidPolicy().equals(id_p))
+            {
+                PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+                p_node.removeChild(node);
+                nodes_i.remove();
+                for (int k = (i - 1); k >= 0; k--)
+                {
+                    List nodes = policyNodes[k];
+                    for (int l = 0; l < nodes.size(); l++)
+                    {
+                        PKIXPolicyNode node2 = (PKIXPolicyNode)nodes.get(l);
+                        if (!node2.hasChildren())
+                        {
+                            validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, node2);
+                            if (validPolicyTree == null)
+                            {
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return validPolicyTree;
+    }
+    
+    protected static boolean isAnyPolicy(
+        Set policySet)
+    {
+        return policySet == null || policySet.contains(ANY_POLICY) || policySet.isEmpty();
+    }
+    
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/CertStoreCollectionSpi.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/CertStoreCollectionSpi.java
new file mode 100644
index 0000000..e1ac37c
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/CertStoreCollectionSpi.java
@@ -0,0 +1,104 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.cert.CRL;
+import java.security.cert.CRLSelector;
+import java.security.cert.CertSelector;
+import java.security.cert.CertStoreException;
+import java.security.cert.CertStoreParameters;
+import java.security.cert.CertStoreSpi;
+import java.security.cert.Certificate;
+import java.security.cert.CollectionCertStoreParameters;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+public class CertStoreCollectionSpi extends CertStoreSpi
+{
+    private CollectionCertStoreParameters params;
+
+    public CertStoreCollectionSpi(CertStoreParameters params)
+        throws InvalidAlgorithmParameterException
+    {
+        super(params);
+
+        if (!(params instanceof CollectionCertStoreParameters))
+        {
+            throw new InvalidAlgorithmParameterException("org.bouncycastle.jce.provider.CertStoreCollectionSpi: parameter must be a CollectionCertStoreParameters object\n" +  params.toString());
+        }
+
+        this.params = (CollectionCertStoreParameters)params;
+    }
+
+    public Collection engineGetCertificates(
+        CertSelector selector)
+        throws CertStoreException 
+    {
+        Set         col = new HashSet();
+        Iterator    iter = params.getCollection().iterator();
+
+        if (selector == null)
+        {
+            while (iter.hasNext())
+            {
+                Object obj = iter.next();
+
+                if (obj instanceof Certificate)
+                {
+                    col.add(obj);
+                }
+            }
+        }
+        else
+        {
+            while (iter.hasNext())
+            {
+                Object obj = iter.next();
+
+                if ((obj instanceof Certificate) && selector.match((Certificate)obj))
+                {
+                    col.add(obj);
+                }
+            }
+        }
+        
+        return col;
+    }
+    
+
+    public Collection engineGetCRLs(
+        CRLSelector selector)
+        throws CertStoreException 
+    {
+        Set         col = new HashSet();
+        Iterator    iter = params.getCollection().iterator();
+
+        if (selector == null)
+        {
+            while (iter.hasNext())
+            {
+                Object obj = iter.next();
+
+                if (obj instanceof CRL)
+                {
+                    col.add(obj);
+                }
+            }
+        }
+        else
+        {
+            while (iter.hasNext())
+            {
+                Object obj = iter.next();
+
+                if ((obj instanceof CRL) && selector.match((CRL)obj))
+                {
+                    col.add(obj);
+                }
+            }
+        }
+        
+        return col;
+    }    
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/DHUtil.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/DHUtil.java
new file mode 100644
index 0000000..2470af9
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/DHUtil.java
@@ -0,0 +1,50 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.DHParameters;
+import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import org.bouncycastle.crypto.params.DHPublicKeyParameters;
+
+/**
+ * utility class for converting jce/jca DH objects
+ * objects into their org.bouncycastle.crypto counterparts.
+ */
+public class DHUtil
+{
+    static public AsymmetricKeyParameter generatePublicKeyParameter(
+        PublicKey    key)
+        throws InvalidKeyException
+    {
+        if (key instanceof DHPublicKey)
+        {
+            DHPublicKey    k = (DHPublicKey)key;
+
+            return new DHPublicKeyParameters(k.getY(),
+                new DHParameters(k.getParams().getP(), k.getParams().getG(), null, k.getParams().getL()));
+        }
+
+        throw new InvalidKeyException("can't identify DH public key.");
+    }
+
+    static public AsymmetricKeyParameter generatePrivateKeyParameter(
+        PrivateKey    key)
+        throws InvalidKeyException
+    {
+        if (key instanceof DHPrivateKey)
+        {
+            DHPrivateKey    k = (DHPrivateKey)key;
+
+            return new DHPrivateKeyParameters(k.getX(),
+                new DHParameters(k.getParams().getP(), k.getParams().getG(), null, k.getParams().getL()));
+        }
+                        
+        throw new InvalidKeyException("can't identify DH private key.");
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/DSAUtil.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/DSAUtil.java
new file mode 100644
index 0000000..5cf3c22
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/DSAUtil.java
@@ -0,0 +1,49 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.DSAPublicKey;
+
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.DSAParameters;
+import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
+
+/**
+ * utility class for converting jce/jca DSA objects
+ * objects into their org.bouncycastle.crypto counterparts.
+ */
+public class DSAUtil
+{
+    static public AsymmetricKeyParameter generatePublicKeyParameter(
+        PublicKey    key)
+        throws InvalidKeyException
+    {
+        if (key instanceof DSAPublicKey)
+        {
+            DSAPublicKey    k = (DSAPublicKey)key;
+
+            return new DSAPublicKeyParameters(k.getY(),
+                new DSAParameters(k.getParams().getP(), k.getParams().getQ(), k.getParams().getG()));
+        }
+
+        throw new InvalidKeyException("can't identify DSA public key: " + key.getClass().getName());
+    }
+
+    static public AsymmetricKeyParameter generatePrivateKeyParameter(
+        PrivateKey    key)
+        throws InvalidKeyException
+    {
+        if (key instanceof DSAPrivateKey)
+        {
+            DSAPrivateKey    k = (DSAPrivateKey)key;
+
+            return new DSAPrivateKeyParameters(k.getX(),
+                new DSAParameters(k.getParams().getP(), k.getParams().getQ(), k.getParams().getG()));
+        }
+                        
+        throw new InvalidKeyException("can't identify DSA private key.");
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEBlockCipher.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEBlockCipher.java
new file mode 100644
index 0000000..85b94e0
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEBlockCipher.java
@@ -0,0 +1,930 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+import javax.crypto.spec.RC5ParameterSpec;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.BufferedBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.engines.*;
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.modes.CFBBlockCipher;
+import org.bouncycastle.crypto.modes.CTSBlockCipher;
+import org.bouncycastle.crypto.modes.GOFBBlockCipher;
+import org.bouncycastle.crypto.modes.OFBBlockCipher;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.modes.OpenPGPCFBBlockCipher;
+// import org.bouncycastle.crypto.modes.PGPCFBBlockCipher;
+// END android-removed
+import org.bouncycastle.crypto.modes.SICBlockCipher;
+import org.bouncycastle.crypto.paddings.ISO10126d2Padding;
+import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
+import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
+import org.bouncycastle.crypto.paddings.TBCPadding;
+import org.bouncycastle.crypto.paddings.X923Padding;
+import org.bouncycastle.crypto.paddings.ZeroBytePadding;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.crypto.params.ParametersWithSBox;
+import org.bouncycastle.crypto.params.RC2Parameters;
+import org.bouncycastle.crypto.params.RC5Parameters;
+// BEGIN android-removed
+// import org.bouncycastle.jce.spec.GOST28147ParameterSpec;
+// END android-removed
+import org.bouncycastle.util.Strings;
+
+public class JCEBlockCipher extends WrapCipherSpi
+    implements PBE
+{
+    //
+    // specs we can handle.
+    //
+    private Class[]                 availableSpecs =
+                                    {
+                                        RC2ParameterSpec.class,
+                                        RC5ParameterSpec.class,
+                                        IvParameterSpec.class,
+                                        PBEParameterSpec.class,
+                                        //GOST28147ParameterSpec.class
+                                    };
+ 
+    private BlockCipher             baseEngine;
+    private BufferedBlockCipher     cipher;
+    private ParametersWithIV        ivParam;
+
+    private int                     ivLength = 0;
+
+    private boolean                 padded = true;
+    
+    private PBEParameterSpec        pbeSpec = null;
+    private String                  pbeAlgorithm = null;
+    
+    private String                  modeName = null;
+
+    protected JCEBlockCipher(
+        BlockCipher engine)
+    {
+        baseEngine = engine;
+
+        cipher = new PaddedBufferedBlockCipher(engine);
+    }
+        
+    protected JCEBlockCipher(
+        BlockCipher engine,
+        int         ivLength)
+    {
+        baseEngine = engine;
+
+        this.cipher = new PaddedBufferedBlockCipher(engine);
+        this.ivLength = ivLength / 8;
+    }
+
+    protected int engineGetBlockSize() 
+    {
+        return baseEngine.getBlockSize();
+    }
+
+    protected byte[] engineGetIV() 
+    {
+        return (ivParam != null) ? ivParam.getIV() : null;
+    }
+
+    protected int engineGetKeySize(
+        Key     key) 
+    {
+        return key.getEncoded().length * 8;
+    }
+
+    protected int engineGetOutputSize(
+        int     inputLen) 
+    {
+        return cipher.getOutputSize(inputLen);
+    }
+
+    protected AlgorithmParameters engineGetParameters() 
+    {
+        if (engineParams == null)
+        {
+            if (pbeSpec != null)
+            {
+                try
+                {
+                    engineParams = AlgorithmParameters.getInstance(pbeAlgorithm, "BC");
+                    engineParams.init(pbeSpec);
+                }
+                catch (Exception e)
+                {
+                    return null;
+                }
+            }
+            else if (ivParam != null)
+            {
+                String  name = cipher.getUnderlyingCipher().getAlgorithmName();
+
+                if (name.indexOf('/') >= 0)
+                {
+                    name = name.substring(0, name.indexOf('/'));
+                }
+
+                try
+                {
+                    engineParams = AlgorithmParameters.getInstance(name, "BC");
+                    engineParams.init(ivParam.getIV());
+                }
+                catch (Exception e)
+                {
+                    throw new RuntimeException(e.toString());
+                }
+            }
+        }
+
+        return engineParams;
+    }
+
+    protected void engineSetMode(
+        String  mode)
+        throws NoSuchAlgorithmException
+    {
+        modeName = Strings.toUpperCase(mode);
+
+        if (modeName.equals("ECB"))
+        {
+            ivLength = 0;
+            cipher = new PaddedBufferedBlockCipher(baseEngine);
+        }
+        else if (modeName.equals("CBC"))
+        {
+            ivLength = baseEngine.getBlockSize();
+            cipher = new PaddedBufferedBlockCipher(
+                            new CBCBlockCipher(baseEngine));
+        }
+        else if (modeName.startsWith("OFB"))
+        {
+            ivLength = baseEngine.getBlockSize();
+            if (modeName.length() != 3)
+            {
+                int wordSize = Integer.parseInt(modeName.substring(3));
+
+                cipher = new PaddedBufferedBlockCipher(
+                                new OFBBlockCipher(baseEngine, wordSize));
+            }
+            else
+            {
+                cipher = new PaddedBufferedBlockCipher(
+                        new OFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize()));
+            }
+        }
+        else if (modeName.startsWith("CFB"))
+        {
+            ivLength = baseEngine.getBlockSize();
+            if (modeName.length() != 3)
+            {
+                int wordSize = Integer.parseInt(modeName.substring(3));
+
+                cipher = new PaddedBufferedBlockCipher(
+                                new CFBBlockCipher(baseEngine, wordSize));
+            }
+            else
+            {
+                cipher = new PaddedBufferedBlockCipher(
+                        new CFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize()));
+            }
+        }
+        // BEGIN android-removed
+        // else if (modeName.startsWith("PGP"))
+        // {
+        //     if (modeName.equalsIgnoreCase("PGPCFBwithIV"))
+        //     {
+        //         ivLength = baseEngine.getBlockSize();
+        //         cipher = new PaddedBufferedBlockCipher(
+        //             new PGPCFBBlockCipher(baseEngine, true));
+        //     }
+        //     else
+        //     {
+        //         ivLength = baseEngine.getBlockSize();
+        //         cipher = new PaddedBufferedBlockCipher(
+        //             new PGPCFBBlockCipher(baseEngine, false));
+        //     }
+        // }
+        // else if (modeName.equalsIgnoreCase("OpenPGPCFB"))
+        // {
+        //     ivLength = 0;
+        //     cipher = new PaddedBufferedBlockCipher(
+        //         new OpenPGPCFBBlockCipher(baseEngine));
+        // }
+        // END android-removed
+        else if (modeName.startsWith("SIC"))
+        {
+            ivLength = baseEngine.getBlockSize();
+            if (ivLength < 16)
+            {
+                throw new IllegalArgumentException("Warning: SIC-Mode can become a twotime-pad if the blocksize of the cipher is too small. Use a cipher with a block size of at least 128 bits (e.g. AES)");
+            }
+            cipher = new BufferedBlockCipher(
+                        new SICBlockCipher(baseEngine));
+        }
+        else if (modeName.startsWith("CTR"))
+        {
+            ivLength = baseEngine.getBlockSize();
+            cipher = new BufferedBlockCipher(
+                        new SICBlockCipher(baseEngine));
+        }
+        else if (modeName.startsWith("GOFB"))
+        {
+            ivLength = baseEngine.getBlockSize();
+            cipher = new BufferedBlockCipher(
+                        new GOFBBlockCipher(baseEngine));
+        }
+        else if (modeName.startsWith("CTS"))
+        {
+            ivLength = baseEngine.getBlockSize();
+            cipher = new CTSBlockCipher(new CBCBlockCipher(baseEngine));
+        }
+        else
+        {
+            throw new NoSuchAlgorithmException("can't support mode " + mode);
+        }
+    }
+
+    protected void engineSetPadding(
+        String  padding) 
+    throws NoSuchPaddingException
+    {
+        String  paddingName = Strings.toUpperCase(padding);
+
+        if (paddingName.equals("NOPADDING"))
+        {
+            padded = false;
+            
+            if (!(cipher instanceof CTSBlockCipher))
+            {
+                cipher = new BufferedBlockCipher(cipher.getUnderlyingCipher());
+            }
+        }
+        else if (paddingName.equals("PKCS5PADDING") || paddingName.equals("PKCS7PADDING"))
+        {
+            cipher = new PaddedBufferedBlockCipher(cipher.getUnderlyingCipher());
+        }
+        else if (paddingName.equals("ZEROBYTEPADDING"))
+        {
+            cipher = new PaddedBufferedBlockCipher(cipher.getUnderlyingCipher(), new ZeroBytePadding());
+        }
+        else if (paddingName.equals("ISO10126PADDING") || paddingName.equals("ISO10126-2PADDING"))
+        {
+            cipher = new PaddedBufferedBlockCipher(cipher.getUnderlyingCipher(), new ISO10126d2Padding());
+        }
+        else if (paddingName.equals("X9.23PADDING") || paddingName.equals("X923PADDING"))
+        {
+            cipher = new PaddedBufferedBlockCipher(cipher.getUnderlyingCipher(), new X923Padding());
+        }
+        else if (paddingName.equals("ISO7816-4PADDING") || paddingName.equals("ISO9797-1PADDING"))
+        {
+            cipher = new PaddedBufferedBlockCipher(cipher.getUnderlyingCipher(), new ISO7816d4Padding());
+        }
+        else if (paddingName.equals("TBCPADDING"))
+        {
+            cipher = new PaddedBufferedBlockCipher(cipher.getUnderlyingCipher(), new TBCPadding());
+        }
+        else if (paddingName.equals("WITHCTS"))
+        {
+            padded = false;
+            cipher = new CTSBlockCipher(cipher.getUnderlyingCipher());
+        }
+        else
+        {
+            throw new NoSuchPaddingException("Padding " + padding + " unknown.");
+        }
+    }
+
+    protected void engineInit(
+        int                     opmode,
+        Key                     key,
+        AlgorithmParameterSpec  params,
+        SecureRandom            random) 
+        throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        CipherParameters        param;
+        
+        this.pbeSpec = null;
+        this.pbeAlgorithm = null;
+        this.engineParams = null;
+        
+        //
+        // basic key check
+        //
+        if (!(key instanceof SecretKey))
+        {
+            throw new InvalidKeyException("Key for algorithm " + key.getAlgorithm() + " not suitable for symmetric enryption.");
+        }
+        
+        //
+        // for RC5-64 we must have some default parameters
+        //
+        if (params == null && baseEngine.getAlgorithmName().startsWith("RC5-64"))
+        {
+            throw new InvalidAlgorithmParameterException("RC5 requires an RC5ParametersSpec to be passed in.");
+        }
+
+        //
+        // a note on iv's - if ivLength is zero the IV gets ignored (we don't use it).
+        //
+        if (key instanceof JCEPBEKey)
+        {
+            JCEPBEKey   k = (JCEPBEKey)key;
+            
+            if (k.getOID() != null)
+            {
+                pbeAlgorithm = k.getOID().getId();
+            }
+            else
+            {
+                pbeAlgorithm = k.getAlgorithm();
+            }
+            
+            if (k.getParam() != null)
+            {
+                param = k.getParam();
+                pbeSpec = new PBEParameterSpec(k.getSalt(), k.getIterationCount());
+            }
+            else if (params instanceof PBEParameterSpec)
+            {
+                pbeSpec = (PBEParameterSpec)params;
+                param = PBE.Util.makePBEParameters(k, params, cipher.getUnderlyingCipher().getAlgorithmName());
+            }
+            else
+            {
+                throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
+            }
+
+            if (param instanceof ParametersWithIV)
+            {
+                ivParam = (ParametersWithIV)param;
+            }
+        }
+        else if (params == null)
+        {
+            param = new KeyParameter(key.getEncoded());
+        }
+        else if (params instanceof IvParameterSpec)
+        {
+            if (ivLength != 0)
+            {
+                IvParameterSpec p = (IvParameterSpec)params;
+
+                if (p.getIV().length != ivLength)
+                {
+                    throw new InvalidAlgorithmParameterException("IV must be " + ivLength + " bytes long.");
+                }
+
+                param = new ParametersWithIV(new KeyParameter(key.getEncoded()), p.getIV());
+                ivParam = (ParametersWithIV)param;
+            }
+            else
+            {
+                if (modeName != null && modeName.equals("ECB"))
+                {
+                    throw new InvalidAlgorithmParameterException("ECB mode does not use an IV");
+                }
+                
+                param = new KeyParameter(key.getEncoded());
+            }
+        }
+        // BEGIN android-removed
+        // else if (params instanceof GOST28147ParameterSpec)
+        // {
+        //     GOST28147ParameterSpec    gost28147Param = (GOST28147ParameterSpec)params;
+        //
+        //     param = new ParametersWithSBox(
+        //                new KeyParameter(key.getEncoded()), ((GOST28147ParameterSpec)params).getSbox());
+        //
+        //     if (gost28147Param.getIV() != null && ivLength != 0)
+        //     {
+        //         param = new ParametersWithIV(param, gost28147Param.getIV());
+        //         ivParam = (ParametersWithIV)param;
+        //     }
+        // }
+        // END android-removed
+        else if (params instanceof RC2ParameterSpec)
+        {
+            RC2ParameterSpec    rc2Param = (RC2ParameterSpec)params;
+
+            param = new RC2Parameters(key.getEncoded(), ((RC2ParameterSpec)params).getEffectiveKeyBits());
+
+            if (rc2Param.getIV() != null && ivLength != 0)
+            {
+                param = new ParametersWithIV(param, rc2Param.getIV());
+                ivParam = (ParametersWithIV)param;
+            }
+        }
+        else if (params instanceof RC5ParameterSpec)
+        {
+            RC5ParameterSpec    rc5Param = (RC5ParameterSpec)params;
+
+            param = new RC5Parameters(key.getEncoded(), ((RC5ParameterSpec)params).getRounds());
+            if (baseEngine.getAlgorithmName().startsWith("RC5"))
+            {
+                if (baseEngine.getAlgorithmName().equals("RC5-32"))
+                {
+                    if (rc5Param.getWordSize() != 32)
+                    {
+                        throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 32 not " + rc5Param.getWordSize() + ".");
+                    }
+                }
+                else if (baseEngine.getAlgorithmName().equals("RC5-64"))
+                {
+                    if (rc5Param.getWordSize() != 64)
+                    {
+                        throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 64 not " + rc5Param.getWordSize() + ".");
+                    }
+                }
+            }
+            else
+            {
+                throw new InvalidAlgorithmParameterException("RC5 parameters passed to a cipher that is not RC5.");
+            }
+            if ((rc5Param.getIV() != null) && (ivLength != 0))
+            {
+                param = new ParametersWithIV(param, rc5Param.getIV());
+                ivParam = (ParametersWithIV)param;
+            }
+        }
+        else
+        {
+            throw new InvalidAlgorithmParameterException("unknown parameter type.");
+        }
+
+        if ((ivLength != 0) && !(param instanceof ParametersWithIV))
+        {
+            SecureRandom    ivRandom = random;
+
+            if (ivRandom == null)
+            {
+                ivRandom = new SecureRandom();
+            }
+
+            if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE))
+            {
+                byte[]  iv = new byte[ivLength];
+
+                ivRandom.nextBytes(iv);
+                param = new ParametersWithIV(param, iv);
+                ivParam = (ParametersWithIV)param;
+            }
+            else if (cipher.getUnderlyingCipher().getAlgorithmName().indexOf("PGPCFB") < 0)
+            {
+                throw new InvalidAlgorithmParameterException("no IV set when one expected");
+            }
+        }
+
+        if (random != null && padded)
+        {
+            param = new ParametersWithRandom(param, random);
+        }
+
+        try
+        {
+            switch (opmode)
+            {
+            case Cipher.ENCRYPT_MODE:
+            case Cipher.WRAP_MODE:
+                cipher.init(true, param);
+                break;
+            case Cipher.DECRYPT_MODE:
+            case Cipher.UNWRAP_MODE:
+                cipher.init(false, param);
+                break;
+            default:
+                throw new InvalidParameterException("unknown opmode " + opmode + " passed");
+            }
+        }
+        catch (Exception e)
+        {
+            throw new InvalidKeyException(e.getMessage());
+        }
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key                 key,
+        AlgorithmParameters params,
+        SecureRandom        random) 
+    throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        AlgorithmParameterSpec  paramSpec = null;
+
+        if (params != null)
+        {
+            for (int i = 0; i != availableSpecs.length; i++)
+            {
+                try
+                {
+                    paramSpec = params.getParameterSpec(availableSpecs[i]);
+                    break;
+                }
+                catch (Exception e)
+                {
+                    continue;
+                }
+            }
+
+            if (paramSpec == null)
+            {
+                throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString());
+            }
+        }
+
+        engineInit(opmode, key, paramSpec, random);
+        
+        engineParams = params;
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key                 key,
+        SecureRandom        random) 
+        throws InvalidKeyException
+    {
+        try
+        {
+            engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+        }
+        catch (InvalidAlgorithmParameterException e)
+        {
+            throw new InvalidKeyException(e.getMessage());
+        }
+    }
+
+    protected byte[] engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen) 
+    {
+        int     length = cipher.getUpdateOutputSize(inputLen);
+
+        if (length > 0)
+        {
+                byte[]  out = new byte[length];
+
+                int len = cipher.processBytes(input, inputOffset, inputLen, out, 0);
+
+                if (len == 0)
+                {
+                    return null;
+                }
+                else if (len != out.length)
+                {
+                    byte[]  tmp = new byte[len];
+
+                    System.arraycopy(out, 0, tmp, 0, len);
+
+                    return tmp;
+                }
+
+                return out;
+        }
+
+        cipher.processBytes(input, inputOffset, inputLen, null, 0);
+
+        return null;
+    }
+
+    protected int engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset)
+        throws ShortBufferException
+    {
+        try
+        {
+            return cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+        }
+        catch (DataLengthException e)
+        {
+            throw new ShortBufferException(e.getMessage());
+        }
+    }
+
+    protected byte[] engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen) 
+        throws IllegalBlockSizeException, BadPaddingException
+    {
+        int     len = 0;
+        byte[]  tmp = new byte[engineGetOutputSize(inputLen)];
+
+        if (inputLen != 0)
+        {
+            len = cipher.processBytes(input, inputOffset, inputLen, tmp, 0);
+        }
+
+        try
+        {
+            len += cipher.doFinal(tmp, len);
+        }
+        catch (DataLengthException e)
+        {
+            throw new IllegalBlockSizeException(e.getMessage());
+        }
+        catch (InvalidCipherTextException e)
+        {
+            throw new BadPaddingException(e.getMessage());
+        }
+
+        byte[]  out = new byte[len];
+
+        System.arraycopy(tmp, 0, out, 0, len);
+
+        return out;
+    }
+
+    protected int engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset) 
+        throws IllegalBlockSizeException, BadPaddingException
+    {
+        int     len = 0;
+
+        if (inputLen != 0)
+        {
+                len = cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+        }
+
+        try
+        {
+            return (len + cipher.doFinal(output, outputOffset + len));
+        }
+        catch (DataLengthException e)
+        {
+            throw new IllegalBlockSizeException(e.getMessage());
+        }
+        catch (InvalidCipherTextException e)
+        {
+            throw new BadPaddingException(e.getMessage());
+        }
+    }
+
+    /*
+     * The ciphers that inherit from us.
+     */
+
+    /**
+     * DES
+     */
+    static public class DES
+        extends JCEBlockCipher
+    {
+        public DES()
+        {
+            super(new DESEngine());
+        }
+    }
+
+    /**
+     * DESCBC
+     */
+    static public class DESCBC
+        extends JCEBlockCipher
+    {
+        public DESCBC()
+        {
+            super(new CBCBlockCipher(new DESEngine()), 64);
+        }
+    }
+
+    /**
+     * DESede
+     */
+    static public class DESede
+        extends JCEBlockCipher
+    {
+        public DESede()
+        {
+            super(new DESedeEngine());
+        }
+    }
+
+    /**
+     * DESedeCBC
+     */
+    static public class DESedeCBC
+        extends JCEBlockCipher
+    {
+        public DESedeCBC()
+        {
+            super(new CBCBlockCipher(new DESedeEngine()), 64);
+        }
+    }
+
+    /**
+     *  GOST28147
+     */
+    // BEGIN android-removed
+    // static public class GOST28147
+    //     extends JCEBlockCipher
+    // {
+    //     public GOST28147()
+    //     {
+    //         super(new GOST28147Engine());
+    //     }
+    // }
+    //
+    // static public class GOST28147cbc
+    //     extends JCEBlockCipher
+    // {
+    //     public GOST28147cbc()
+    //     {
+    //         super(new CBCBlockCipher(new GOST28147Engine()), 64);
+    //     }
+    // }
+    // END android-removed
+
+    /**
+     * AES
+     */
+    static public class AES
+        extends JCEBlockCipher
+    {
+        public AES()
+        {
+            super(new AESFastEngine());
+        }
+    }
+
+    /**
+     * AESCBC
+     */
+    static public class AESCBC
+        extends JCEBlockCipher
+    {
+        public AESCBC()
+        {
+            super(new CBCBlockCipher(new AESFastEngine()), 128);
+        }
+    }
+
+    /**
+     * AESCFB
+     */
+    static public class AESCFB
+        extends JCEBlockCipher
+    {
+        public AESCFB()
+        {
+            super(new CFBBlockCipher(new AESFastEngine(), 128), 128);
+        }
+    }
+    
+    /**
+     * AESOFB
+     */
+    static public class AESOFB
+        extends JCEBlockCipher
+    {
+        public AESOFB()
+        {
+            super(new OFBBlockCipher(new AESFastEngine(), 128), 128);
+        }
+    }
+
+    /**
+     * Camellia
+     */
+    // BEGIN android-removed
+    // static public class Camellia
+    //     extends JCEBlockCipher
+    // {
+    //     public Camellia()
+    //     {
+    //         super(new CamelliaEngine());
+    //     }
+    // }
+    // END android-removed
+    
+    /**
+     * CAST5
+     */
+    // BEGIN android-removed
+    // static public class CAST5
+    //     extends JCEBlockCipher
+    // {
+    //     public CAST5()
+    //     {
+    //         super(new CAST5Engine());
+    //     }
+    // }
+    // END android-removed
+
+    /**
+     * CAST5 CBC
+     */
+    // BEGIN android-removed
+    // static public class CAST5CBC
+    //     extends JCEBlockCipher
+    // {
+    //     public CAST5CBC()
+    //     {
+    //         super(new CBCBlockCipher(new CAST5Engine()), 64);
+    //     }
+    // }
+    // END android-removed
+
+    /**
+     * CAST6
+     */
+    // BEGIN android-removed
+    // static public class CAST6
+    //     extends JCEBlockCipher
+    // {
+    //     public CAST6()
+    //     {
+    //         super(new CAST6Engine());
+    //     }
+    // }
+    // BEGIN android-removed
+
+    /**
+     * PBEWithMD5AndDES
+     */
+    static public class PBEWithMD5AndDES
+        extends JCEBlockCipher
+    {
+        public PBEWithMD5AndDES()
+        {
+            super(new CBCBlockCipher(new DESEngine()));
+        }
+    }
+
+    /**
+     * PBEWithSHA1AndDES
+     */
+    static public class PBEWithSHA1AndDES
+        extends JCEBlockCipher
+    {
+        public PBEWithSHA1AndDES()
+        {
+            super(new CBCBlockCipher(new DESEngine()));
+        }
+    }
+
+    /**
+     * PBEWithSHAAnd3-KeyTripleDES-CBC
+     */
+    static public class PBEWithSHAAndDES3Key
+        extends JCEBlockCipher
+    {
+        public PBEWithSHAAndDES3Key()
+        {
+            super(new CBCBlockCipher(new DESedeEngine()));
+        }
+    }
+
+    /**
+     * PBEWithSHAAnd2-KeyTripleDES-CBC
+     */
+    static public class PBEWithSHAAndDES2Key
+        extends JCEBlockCipher
+    {
+        public PBEWithSHAAndDES2Key()
+        {
+            super(new CBCBlockCipher(new DESedeEngine()));
+        }
+    }
+    
+    /**
+     * PBEWithAES-CBC
+     */
+    static public class PBEWithAESCBC
+        extends JCEBlockCipher
+    {
+        public PBEWithAESCBC()
+        {
+            super(new CBCBlockCipher(new AESFastEngine()));
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java
new file mode 100644
index 0000000..f215029
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEDHKeyAgreement.java
@@ -0,0 +1,178 @@
+package org.bouncycastle.jce.provider;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.KeyAgreementSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * Diffie-Hellman key agreement. There's actually a better way of doing this
+ * if you are using long term public keys, see the light-weight version for
+ * details.
+ */
+public class JCEDHKeyAgreement
+    extends KeyAgreementSpi
+{
+    private BigInteger      x;
+    private BigInteger      p;
+    private BigInteger      g;
+    private BigInteger      result;
+
+    private SecureRandom    random;
+    
+    private byte[] bigIntToBytes(
+        BigInteger    r)
+    {
+        byte[]    tmp = r.toByteArray();
+        
+        if (tmp[0] == 0)
+        {
+            byte[]    ntmp = new byte[tmp.length - 1];
+            
+            System.arraycopy(tmp, 1, ntmp, 0, ntmp.length);
+            return ntmp;
+        }
+        
+        return tmp;
+    }
+    
+    protected Key engineDoPhase(
+        Key     key,
+        boolean lastPhase) 
+        throws InvalidKeyException, IllegalStateException
+    {
+        if (x == null)
+        {
+            throw new IllegalStateException("Diffie-Hellman not initialised.");
+        }
+
+        if (!(key instanceof DHPublicKey))
+        {
+            throw new InvalidKeyException("DHKeyAgreement doPhase requires DHPublicKey");
+        }
+        DHPublicKey pubKey = (DHPublicKey)key;
+
+        if (!pubKey.getParams().getG().equals(g) || !pubKey.getParams().getP().equals(p))
+        {
+            throw new InvalidKeyException("DHPublicKey not for this KeyAgreement!");
+        }
+
+        if (lastPhase)
+        {
+            result = ((DHPublicKey)key).getY().modPow(x, p);
+            return null;
+        }
+        else
+        {
+            result = ((DHPublicKey)key).getY().modPow(x, p);
+        }
+
+        return new JCEDHPublicKey(result, pubKey.getParams());
+    }
+
+    protected byte[] engineGenerateSecret() 
+        throws IllegalStateException
+    {
+        if (x == null)
+        {
+            throw new IllegalStateException("Diffie-Hellman not initialised.");
+        }
+
+        return bigIntToBytes(result);
+    }
+
+    protected int engineGenerateSecret(
+        byte[]  sharedSecret,
+        int     offset) 
+        throws IllegalStateException, ShortBufferException
+    {
+        if (x == null)
+        {
+            throw new IllegalStateException("Diffie-Hellman not initialised.");
+        }
+
+        byte[]  secret = bigIntToBytes(result);
+
+        if (sharedSecret.length - offset < secret.length)
+        {
+            throw new ShortBufferException("DHKeyAgreement - buffer too short");
+        }
+
+        System.arraycopy(secret, 0, sharedSecret, offset, secret.length);
+
+        return secret.length;
+    }
+
+    protected SecretKey engineGenerateSecret(
+        String algorithm) 
+    {
+        if (x == null)
+        {
+            throw new IllegalStateException("Diffie-Hellman not initialised.");
+        }
+        
+        return new SecretKeySpec(bigIntToBytes(result), algorithm);
+    }
+
+    protected void engineInit(
+        Key                     key,
+        AlgorithmParameterSpec  params,
+        SecureRandom            random) 
+        throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        if (!(key instanceof DHPrivateKey))
+        {
+            throw new InvalidKeyException("DHKeyAgreement requires DHPrivateKey for initialisation");
+        }
+        DHPrivateKey    privKey = (DHPrivateKey)key;
+
+        this.random = random;
+
+        if (params != null)
+        {
+            if (!(params instanceof DHParameterSpec))
+            {
+                throw new InvalidAlgorithmParameterException("DHKeyAgreement only accepts DHParameterSpec");
+            }
+            DHParameterSpec p = (DHParameterSpec)params;
+
+            this.p = p.getP();
+            this.g = p.getG();
+        }
+        else
+        {
+            this.p = privKey.getParams().getP();
+            this.g = privKey.getParams().getG();
+        }
+
+        this.x = this.result = privKey.getX();
+    }
+
+    protected void engineInit(
+        Key             key,
+        SecureRandom    random) 
+        throws InvalidKeyException
+    {
+        if (!(key instanceof DHPrivateKey))
+        {
+            throw new InvalidKeyException("DHKeyAgreement requires DHPrivateKey");
+        }
+
+        DHPrivateKey    privKey = (DHPrivateKey)key;
+
+        this.random = random;
+        this.p = privKey.getParams().getP();
+        this.g = privKey.getParams().getG();
+        this.x = this.result = privKey.getX();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEDHPrivateKey.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEDHPrivateKey.java
new file mode 100644
index 0000000..07c71bf
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEDHPrivateKey.java
@@ -0,0 +1,155 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPrivateKeySpec;
+
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.asn1.pkcs.DHParameter;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+public class JCEDHPrivateKey
+    implements DHPrivateKey, PKCS12BagAttributeCarrier
+{
+    BigInteger      x;
+
+    DHParameterSpec dhSpec;
+
+    private Hashtable   pkcs12Attributes = new Hashtable();
+    private Vector      pkcs12Ordering = new Vector();
+
+    protected JCEDHPrivateKey()
+    {
+    }
+
+    JCEDHPrivateKey(
+        DHPrivateKey    key)
+    {
+        this.x = key.getX();
+        this.dhSpec = key.getParams();
+    }
+
+    JCEDHPrivateKey(
+        DHPrivateKeySpec    spec)
+    {
+        this.x = spec.getX();
+        this.dhSpec = new DHParameterSpec(spec.getP(), spec.getG());
+    }
+
+    JCEDHPrivateKey(
+        PrivateKeyInfo  info)
+    {
+        DHParameter     params = new DHParameter((ASN1Sequence)info.getAlgorithmId().getParameters());
+        DERInteger      derX = (DERInteger)info.getPrivateKey();
+
+        this.x = derX.getValue();
+        if (params.getL() != null)
+        {
+            this.dhSpec = new DHParameterSpec(params.getP(), params.getG(), params.getL().intValue());
+        }
+        else
+        {
+            this.dhSpec = new DHParameterSpec(params.getP(), params.getG());
+        }
+    }
+
+    JCEDHPrivateKey(
+        DHPrivateKeyParameters  params)
+    {
+        this.x = params.getX();
+        this.dhSpec = new DHParameterSpec(params.getParameters().getP(), params.getParameters().getG());
+    }
+
+    public String getAlgorithm()
+    {
+        return "DH";
+    }
+
+    /**
+     * return the encoding format we produce in getEncoded().
+     *
+     * @return the string "PKCS#8"
+     */
+    public String getFormat()
+    {
+        return "PKCS#8";
+    }
+
+    /**
+     * Return a PKCS8 representation of the key. The sequence returned
+     * represents a full PrivateKeyInfo object.
+     *
+     * @return a PKCS8 representation of the key.
+     */
+    public byte[] getEncoded()
+    {
+        PrivateKeyInfo          info = new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL()).getDERObject()), new DERInteger(getX()));
+
+        return info.getDEREncoded();
+    }
+
+    public DHParameterSpec getParams()
+    {
+        return dhSpec;
+    }
+
+    public BigInteger getX()
+    {
+        return x;
+    }
+
+    private void readObject(
+        ObjectInputStream   in)
+        throws IOException, ClassNotFoundException
+    {
+        x = (BigInteger)in.readObject();
+
+        this.dhSpec = new DHParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), in.readInt());
+    }
+
+    private void writeObject(
+        ObjectOutputStream  out)
+        throws IOException
+    {
+        out.writeObject(this.getX());
+        out.writeObject(dhSpec.getP());
+        out.writeObject(dhSpec.getG());
+        out.writeInt(dhSpec.getL());
+    }
+
+    public void setBagAttribute(
+        DERObjectIdentifier oid,
+        DEREncodable        attribute)
+    {
+        pkcs12Attributes.put(oid, attribute);
+        pkcs12Ordering.addElement(oid);
+    }
+
+    public DEREncodable getBagAttribute(
+        DERObjectIdentifier oid)
+    {
+        return (DEREncodable)pkcs12Attributes.get(oid);
+    }
+
+    public Enumeration getBagAttributeKeys()
+    {
+        return pkcs12Ordering.elements();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEDHPublicKey.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEDHPublicKey.java
new file mode 100644
index 0000000..0534b4d
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEDHPublicKey.java
@@ -0,0 +1,127 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPublicKeySpec;
+
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.asn1.pkcs.DHParameter;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.DHPublicKeyParameters;
+
+public class JCEDHPublicKey
+    implements DHPublicKey
+{
+    private BigInteger              y;
+    private DHParameterSpec         dhSpec;
+
+    JCEDHPublicKey(
+        DHPublicKeySpec    spec)
+    {
+        this.y = spec.getY();
+        this.dhSpec = new DHParameterSpec(spec.getP(), spec.getG());
+    }
+
+    JCEDHPublicKey(
+        DHPublicKey    key)
+    {
+        this.y = key.getY();
+        this.dhSpec = key.getParams();
+    }
+
+    JCEDHPublicKey(
+        DHPublicKeyParameters  params)
+    {
+        this.y = params.getY();
+        this.dhSpec = new DHParameterSpec(params.getParameters().getP(), params.getParameters().getG(), 0);
+    }
+
+    JCEDHPublicKey(
+        BigInteger        y,
+        DHParameterSpec   dhSpec)
+    {
+        this.y = y;
+        this.dhSpec = dhSpec;
+    }
+
+    JCEDHPublicKey(
+        SubjectPublicKeyInfo    info)
+    {
+        DHParameter             params = new DHParameter((ASN1Sequence)info.getAlgorithmId().getParameters());
+        DERInteger              derY = null;
+
+        try
+        {
+            derY = (DERInteger)info.getPublicKey();
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("invalid info structure in DH public key");
+        }
+
+        this.y = derY.getValue();
+        if (params.getL() != null)
+        {
+            this.dhSpec = new DHParameterSpec(params.getP(), params.getG(), params.getL().intValue());
+        }
+        else
+        {
+            this.dhSpec = new DHParameterSpec(params.getP(), params.getG());
+        }
+    }
+
+    public String getAlgorithm()
+    {
+        return "DH";
+    }
+
+    public String getFormat()
+    {
+        return "X.509";
+    }
+
+    public byte[] getEncoded()
+    {
+        SubjectPublicKeyInfo    info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.dhpublicnumber, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL()).getDERObject()), new DERInteger(y));
+
+        return info.getDEREncoded();
+    }
+
+    public DHParameterSpec getParams()
+    {
+        return dhSpec;
+    }
+
+    public BigInteger getY()
+    {
+        return y;
+    }
+
+    private void readObject(
+        ObjectInputStream   in)
+        throws IOException, ClassNotFoundException
+    {
+        this.y = (BigInteger)in.readObject();
+        this.dhSpec = new DHParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), in.readInt());
+    }
+
+    private void writeObject(
+        ObjectOutputStream  out)
+        throws IOException
+    {
+        out.writeObject(this.getY());
+        out.writeObject(dhSpec.getP());
+        out.writeObject(dhSpec.getG());
+        out.writeInt(dhSpec.getL());
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEDigestUtil.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEDigestUtil.java
new file mode 100644
index 0000000..a9f6d6a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEDigestUtil.java
@@ -0,0 +1,131 @@
+package org.bouncycastle.jce.provider;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.MD5Digest;
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.digests.SHA224Digest;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.digests.SHA384Digest;
+import org.bouncycastle.crypto.digests.SHA512Digest;
+import org.bouncycastle.util.Strings;
+
+class JCEDigestUtil
+{
+    private static Set md5 = new HashSet();
+    private static Set sha1 = new HashSet();
+    private static Set sha224 = new HashSet();
+    private static Set sha256 = new HashSet();
+    private static Set sha384 = new HashSet();
+    private static Set sha512 = new HashSet();
+    
+    private static Map oids = new HashMap();
+    
+    static
+    {
+        md5.add("MD5");
+        md5.add(PKCSObjectIdentifiers.md5.getId());
+        
+        sha1.add("SHA1");
+        sha1.add("SHA-1");
+        sha1.add(OIWObjectIdentifiers.idSHA1.getId());
+        
+        sha224.add("SHA224");
+        sha224.add("SHA-224");
+        sha224.add(NISTObjectIdentifiers.id_sha224.getId());
+        
+        sha256.add("SHA256");
+        sha256.add("SHA-256");
+        sha256.add(NISTObjectIdentifiers.id_sha256.getId());
+        
+        sha384.add("SHA384");
+        sha384.add("SHA-384");
+        sha384.add(NISTObjectIdentifiers.id_sha384.getId());
+        
+        sha512.add("SHA512");
+        sha512.add("SHA-512");
+        sha512.add(NISTObjectIdentifiers.id_sha512.getId()); 
+
+        oids.put("MD5", PKCSObjectIdentifiers.md5);
+        oids.put(PKCSObjectIdentifiers.md5.getId(), PKCSObjectIdentifiers.md5);
+        
+        oids.put("SHA1", OIWObjectIdentifiers.idSHA1);
+        oids.put("SHA-1", OIWObjectIdentifiers.idSHA1);
+        oids.put(OIWObjectIdentifiers.idSHA1.getId(), OIWObjectIdentifiers.idSHA1);
+        
+        oids.put("SHA224", NISTObjectIdentifiers.id_sha224);
+        oids.put("SHA-224", NISTObjectIdentifiers.id_sha224);
+        oids.put(NISTObjectIdentifiers.id_sha224.getId(), NISTObjectIdentifiers.id_sha224);
+        
+        oids.put("SHA256", NISTObjectIdentifiers.id_sha256);
+        oids.put("SHA-256", NISTObjectIdentifiers.id_sha256);
+        oids.put(NISTObjectIdentifiers.id_sha256.getId(), NISTObjectIdentifiers.id_sha256);
+        
+        oids.put("SHA384", NISTObjectIdentifiers.id_sha384);
+        oids.put("SHA-384", NISTObjectIdentifiers.id_sha384);
+        oids.put(NISTObjectIdentifiers.id_sha384.getId(), NISTObjectIdentifiers.id_sha384);
+        
+        oids.put("SHA512", NISTObjectIdentifiers.id_sha512);
+        oids.put("SHA-512", NISTObjectIdentifiers.id_sha512);
+        oids.put(NISTObjectIdentifiers.id_sha512.getId(), NISTObjectIdentifiers.id_sha512); 
+    }
+    
+    static Digest getDigest(
+        String digestName) 
+    {
+        digestName = Strings.toUpperCase(digestName);
+        
+        if (sha1.contains(digestName))
+        {
+            return new SHA1Digest();
+        }
+        if (md5.contains(digestName))
+        {
+            return new MD5Digest();
+        }
+        if (sha224.contains(digestName))
+        {
+            return new SHA224Digest();
+        }
+        if (sha256.contains(digestName))
+        {
+            return new SHA256Digest();
+        }
+        if (sha384.contains(digestName))
+        {
+            return new SHA384Digest();
+        }
+        if (sha512.contains(digestName))
+        {
+            return new SHA512Digest();
+        }
+        
+        return null;
+    }
+    
+    static boolean isSameDigest(
+        String digest1,
+        String digest2)
+    {
+        return (sha1.contains(digest1) && sha1.contains(digest2))
+            || (sha224.contains(digest1) && sha224.contains(digest2))
+            || (sha256.contains(digest1) && sha256.contains(digest2))
+            || (sha384.contains(digest1) && sha384.contains(digest2))
+            || (sha512.contains(digest1) && sha512.contains(digest2))
+            || (md5.contains(digest1) && md5.contains(digest2));
+    }
+    
+    static DERObjectIdentifier getOID(
+        String digestName)
+    {
+        return (DERObjectIdentifier)oids.get(digestName);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEIESCipher.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEIESCipher.java
new file mode 100644
index 0000000..95ee2b6
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEIESCipher.java
@@ -0,0 +1,408 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.interfaces.DHPrivateKey;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.agreement.DHBasicAgreement;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
+// END android-removed
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.engines.IESEngine;
+import org.bouncycastle.crypto.generators.KDF2BytesGenerator;
+import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.crypto.params.IESParameters;
+// BEGIN android-removed
+// import org.bouncycastle.jce.interfaces.ECPrivateKey;
+// import org.bouncycastle.jce.interfaces.ECPublicKey;
+// END android-removed
+import org.bouncycastle.jce.interfaces.IESKey;
+import org.bouncycastle.jce.spec.IESParameterSpec;
+
+public class JCEIESCipher extends WrapCipherSpi
+{
+    private IESEngine               cipher;
+    private int                     state = -1;
+    private ByteArrayOutputStream   buffer = new ByteArrayOutputStream();
+    private AlgorithmParameters     engineParam = null;
+    private IESParameterSpec        engineParams = null;
+
+    //
+    // specs we can handle.
+    //
+    private Class[]                 availableSpecs =
+                                    {
+                                        IESParameterSpec.class
+                                    };
+
+    public JCEIESCipher(
+        IESEngine   engine)
+    {
+        cipher = engine;
+    }
+
+    protected int engineGetBlockSize() 
+    {
+        return 0;
+    }
+
+    protected byte[] engineGetIV() 
+    {
+        return null;
+    }
+
+    protected int engineGetKeySize(
+        Key     key) 
+    {
+        IESKey   ieKey = (IESKey)key;
+
+        if (ieKey.getPrivate() instanceof DHPrivateKey)
+        {
+            DHPrivateKey   k = (DHPrivateKey)ieKey.getPrivate();
+
+            return k.getX().bitLength();
+        }
+        // BEGIN android-removed
+        // else if (ieKey.getPrivate() instanceof ECPrivateKey)
+        // {
+        //     ECPrivateKey   k = (ECPrivateKey)ieKey.getPrivate();
+        //
+        //     return k.getD().bitLength();
+        // }
+        // END android-removed
+
+        throw new IllegalArgumentException("not an IE key!");
+    }
+
+    protected int engineGetOutputSize(
+        int     inputLen) 
+    {
+        if (state == Cipher.ENCRYPT_MODE || state == Cipher.WRAP_MODE)
+        {
+            return buffer.size() + inputLen + 20; /* SHA1 MAC size */
+        }
+        else if (state == Cipher.DECRYPT_MODE || state == Cipher.UNWRAP_MODE)
+        {
+            return buffer.size() + inputLen - 20;
+        }
+        else
+        {
+            throw new IllegalStateException("cipher not initialised");
+        }
+    }
+
+    protected AlgorithmParameters engineGetParameters() 
+    {
+        if (engineParam == null)
+        {
+            if (engineParams != null)
+            {
+                String  name = "IES";
+
+                try
+                {
+                    engineParam = AlgorithmParameters.getInstance(name, "BC");
+                    engineParam.init(engineParams);
+                }
+                catch (Exception e)
+                {
+                    throw new RuntimeException(e.toString());
+                }
+            }
+        }
+
+        return engineParam;
+    }
+
+    protected void engineSetMode(
+        String  mode) 
+    {
+        throw new IllegalArgumentException("can't support mode " + mode);
+    }
+
+    protected void engineSetPadding(
+        String  padding) 
+        throws NoSuchPaddingException
+    {
+        throw new NoSuchPaddingException(padding + " unavailable with RSA.");
+    }
+
+    protected void engineInit(
+        int                     opmode,
+        Key                     key,
+        AlgorithmParameterSpec  params,
+        SecureRandom            random) 
+    throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        if (!(key instanceof IESKey))
+        {
+            throw new InvalidKeyException("must be passed IE key");
+        }
+
+        if (params == null && (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE))
+        {
+            //
+            // if nothing is specified we set up for a 128 bit mac, with
+            // 128 bit derivation vectors.
+            //
+            byte[]  d = new byte[16];
+            byte[]  e = new byte[16];
+
+            if (random == null)
+            {
+                random = new SecureRandom();
+            }
+
+            random.nextBytes(d);
+            random.nextBytes(e);
+
+            params = new IESParameterSpec(d, e, 128);
+        }
+        else if (!(params instanceof IESParameterSpec))
+        {
+            throw new InvalidAlgorithmParameterException("must be passed IES parameters");
+        }
+
+        IESKey       ieKey = (IESKey)key;
+
+        CipherParameters pubKey;
+        CipherParameters privKey;
+
+        // BEGIN android-removed
+        // if (ieKey.getPublic() instanceof ECPublicKey)
+        // {
+        //     pubKey = ECUtil.generatePublicKeyParameter(ieKey.getPublic());
+        //     privKey = ECUtil.generatePrivateKeyParameter(ieKey.getPrivate());
+        // }
+        // else
+        // {
+        // END android-removed
+            pubKey = DHUtil.generatePublicKeyParameter(ieKey.getPublic());
+            privKey = DHUtil.generatePrivateKeyParameter(ieKey.getPrivate());
+        // BEGIN android-removed
+        // }
+        // END android-removed
+
+        this.engineParams = (IESParameterSpec)params;
+
+        IESParameters       p = new IESParameters(engineParams.getDerivationV(), engineParams.getEncodingV(), engineParams.getMacKeySize());
+
+        this.state = opmode;
+
+        buffer.reset();
+
+        switch (opmode)
+        {
+        case Cipher.ENCRYPT_MODE:
+        case Cipher.WRAP_MODE:
+            cipher.init(true, privKey, pubKey, p);
+            break;
+        case Cipher.DECRYPT_MODE:
+        case Cipher.UNWRAP_MODE:
+            cipher.init(false, privKey, pubKey, p);
+            break;
+        default:
+            System.out.println("eeek!");
+        }
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key                 key,
+        AlgorithmParameters params,
+        SecureRandom        random) 
+    throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        AlgorithmParameterSpec  paramSpec = null;
+
+        if (params != null)
+        {
+            for (int i = 0; i != availableSpecs.length; i++)
+            {
+                try
+                {
+                    paramSpec = params.getParameterSpec(availableSpecs[i]);
+                    break;
+                }
+                catch (Exception e)
+                {
+                    continue;
+                }
+            }
+
+            if (paramSpec == null)
+            {
+                throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString());
+            }
+        }
+
+        engineParam = params;
+        engineInit(opmode, key, paramSpec, random);
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key                 key,
+        SecureRandom        random) 
+    throws InvalidKeyException
+    {
+        if (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE)
+        {
+            try
+            {
+                engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+                return;
+            }
+            catch (InvalidAlgorithmParameterException e)
+            {
+                // fall through...
+            }
+        }
+
+        throw new IllegalArgumentException("can't handle null parameter spec in IES");
+    }
+
+    protected byte[] engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen) 
+    {
+        buffer.write(input, inputOffset, inputLen);
+        return null;
+    }
+
+    protected int engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset) 
+    {
+        buffer.write(input, inputOffset, inputLen);
+        return 0;
+    }
+
+    protected byte[] engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen) 
+        throws IllegalBlockSizeException, BadPaddingException
+    {
+        if (inputLen != 0)
+        {
+            buffer.write(input, inputOffset, inputLen);
+        }
+
+        try
+        {
+            byte[]  buf = buffer.toByteArray();
+
+            buffer.reset();
+
+            return cipher.processBlock(buf, 0, buf.length);
+        }
+        catch (InvalidCipherTextException e)
+        {
+            throw new BadPaddingException(e.getMessage());
+        }
+    }
+
+    protected int engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset) 
+        throws IllegalBlockSizeException, BadPaddingException
+    {
+        if (inputLen != 0)
+        {
+            buffer.write(input, inputOffset, inputLen);
+        }
+
+        try
+        {
+            byte[]  buf = buffer.toByteArray();
+
+            buffer.reset();
+
+            buf = cipher.processBlock(buf, 0, buf.length);
+
+            System.arraycopy(buf, 0, output, outputOffset, buf.length);
+
+            return buf.length;
+        }
+        catch (InvalidCipherTextException e)
+        {
+            throw new BadPaddingException(e.getMessage());
+        }
+    }
+
+    /**
+     * classes that inherit from us.
+     */
+// BEGIN android-removed
+//    static public class BrokenECIES
+//        extends JCEIESCipher
+//    {
+//        public BrokenECIES()
+//        {
+//            super(new IESEngine(
+//                   new ECDHBasicAgreement(),
+//                   new BrokenKDF2BytesGenerator(new SHA1Digest()),
+//                   new HMac(new SHA1Digest())));
+//        }
+//    }
+// END android-removed
+
+    static public class BrokenIES
+        extends JCEIESCipher
+    {
+        public BrokenIES()
+        {
+            super(new IESEngine(
+                   new DHBasicAgreement(),
+                   new BrokenKDF2BytesGenerator(new SHA1Digest()),
+                   new HMac(new SHA1Digest())));
+        }
+    }
+    
+// BEGIN android-removed
+//    static public class ECIES
+//        extends JCEIESCipher
+//    {
+//        public ECIES()
+//        {
+//            super(new IESEngine(
+//                   new ECDHBasicAgreement(),
+//                   new KDF2BytesGenerator(new SHA1Digest()),
+//                   new HMac(new SHA1Digest())));
+//        }
+//    }
+// END android-removed
+    
+    static public class IES
+        extends JCEIESCipher
+    {
+        public IES()
+        {
+            super(new IESEngine(
+                   new DHBasicAgreement(),
+                   new KDF2BytesGenerator(new SHA1Digest()),
+                   new HMac(new SHA1Digest())));
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEKeyGenerator.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEKeyGenerator.java
new file mode 100644
index 0000000..681de84
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEKeyGenerator.java
@@ -0,0 +1,539 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.KeyGeneratorSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.crypto.CipherKeyGenerator;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.crypto.generators.DESKeyGenerator;
+import org.bouncycastle.crypto.generators.DESedeKeyGenerator;
+
+public class JCEKeyGenerator
+    extends KeyGeneratorSpi
+{
+    protected String                algName;
+    protected int                   keySize;
+    protected int                   defaultKeySize;
+    protected CipherKeyGenerator    engine;
+
+    protected boolean               uninitialised = true;
+
+    protected JCEKeyGenerator(
+        String              algName,
+        int                 defaultKeySize,
+        CipherKeyGenerator  engine)
+    {
+        this.algName = algName;
+        this.keySize = this.defaultKeySize = defaultKeySize;
+        this.engine = engine;
+    }
+
+    protected void engineInit(
+        AlgorithmParameterSpec  params,
+        SecureRandom            random)
+    throws InvalidAlgorithmParameterException
+    {
+        throw new InvalidAlgorithmParameterException("Not Implemented");
+    }
+
+    protected void engineInit(
+        SecureRandom    random)
+    {
+        if (random != null)
+        {
+            uninitialised = false;
+    
+            engine.init(new KeyGenerationParameters(random, defaultKeySize));
+        }
+    }
+
+    protected void engineInit(
+        int             keySize,
+        SecureRandom    random)
+    {
+        uninitialised = false;
+
+        try
+        {
+            engine.init(new KeyGenerationParameters(random, keySize));
+        }
+        catch (IllegalArgumentException e)
+        {
+            throw new InvalidParameterException(e.getMessage());
+        }
+    }
+
+    protected SecretKey engineGenerateKey()
+    {
+        if (uninitialised)
+        {
+            engine.init(new KeyGenerationParameters(
+                                    new SecureRandom(), defaultKeySize));
+        }
+
+        return (SecretKey)(new SecretKeySpec(engine.generateKey(), algName));
+    }
+
+    /**
+     * the generators that are defined directly off us.
+     */
+
+    /**
+     * DES
+     */
+    public static class DES
+        extends JCEKeyGenerator
+    {
+        public DES()
+        {
+            super("DES", 64, new DESKeyGenerator());
+        }
+    }
+
+    /**
+     * DESede - the default for this is to generate a key in 
+     * a-b-a format that's 24 bytes long but has 16 bytes of
+     * key material (the first 8 bytes is repeated as the last
+     * 8 bytes). If you give it a size, you'll get just what you
+     * asked for.
+     */
+    public static class DESede
+        extends JCEKeyGenerator
+    {
+        private boolean     keySizeSet = false;
+
+        public DESede()
+        {
+            super("DESede", 192, new DESedeKeyGenerator());
+        }
+
+        protected void engineInit(
+            int             keySize,
+            SecureRandom    random)
+        {
+            super.engineInit(keySize, random);
+            keySizeSet = true;
+        }
+
+        protected SecretKey engineGenerateKey()
+        {
+            if (uninitialised)
+            {
+                engine.init(new KeyGenerationParameters(
+                                        new SecureRandom(), defaultKeySize));
+            }
+
+            //
+            // if no key size has been defined generate a 24 byte key in
+            // the a-b-a format
+            //
+            if (!keySizeSet)
+            {
+                byte[]     k = engine.generateKey();
+
+                System.arraycopy(k, 0, k, 16, 8);
+
+                return (SecretKey)(new SecretKeySpec(k, algName));
+            }
+            else
+            {
+                return (SecretKey)(new SecretKeySpec(engine.generateKey(), algName));
+            }
+        }
+    }
+    
+    /**
+     * generate a desEDE key in the a-b-c format.
+     */
+    public static class DESede3
+        extends JCEKeyGenerator
+    {
+        private boolean     keySizeSet = false;
+
+        public DESede3()
+        {
+            super("DESede3", 192, new DESedeKeyGenerator());
+        }
+
+        protected void engineInit(
+            int             keySize,
+            SecureRandom    random)
+        {
+            super.engineInit(keySize, random);
+            keySizeSet = true;
+        }
+
+        protected SecretKey engineGenerateKey()
+        {
+            if (uninitialised)
+            {
+                engine.init(new KeyGenerationParameters(
+                                        new SecureRandom(), defaultKeySize));
+            }
+
+            return (SecretKey)(new SecretKeySpec(engine.generateKey(), algName));
+        }
+    }
+
+    /**
+     * SKIPJACK
+     */
+    public static class Skipjack
+        extends JCEKeyGenerator
+    {
+        public Skipjack()
+        {
+            super("SKIPJACK", 80, new CipherKeyGenerator());
+        }
+    }
+
+    /**
+     * Blowfish
+     */
+    public static class Blowfish
+        extends JCEKeyGenerator
+    {
+        public Blowfish()
+        {
+            super("Blowfish", 448, new CipherKeyGenerator());
+        }
+    }
+
+    /**
+     * Twofish
+     */
+    public static class Twofish
+        extends JCEKeyGenerator
+    {
+        public Twofish()
+        {
+            super("Twofish", 256, new CipherKeyGenerator());
+        }
+    }
+
+    /**
+     * RC2
+     */
+    public static class RC2
+        extends JCEKeyGenerator
+    {
+        public RC2()
+        {
+            super("RC2", 128, new CipherKeyGenerator());
+        }
+    }
+
+    /**
+     * RC4
+     */
+    public static class RC4
+        extends JCEKeyGenerator
+    {
+        public RC4()
+        {
+            super("RC4", 128, new CipherKeyGenerator());
+        }
+    }
+
+    /**
+     * RC5
+     */
+    public static class RC5
+        extends JCEKeyGenerator
+    {
+        public RC5()
+        {
+            super("RC5", 128, new CipherKeyGenerator());
+        }
+    }
+
+    /**
+     * RC5
+     */
+    public static class RC564
+        extends JCEKeyGenerator
+    {
+        public RC564()
+        {
+            super("RC5-64", 256, new CipherKeyGenerator());
+        }
+    }
+
+    /**
+     * RC6
+     */
+    public static class RC6
+        extends JCEKeyGenerator
+    {
+        public RC6()
+        {
+            super("RC6", 256, new CipherKeyGenerator());
+        }
+    }
+
+    /**
+     * AES
+     */
+    public static class AES
+        extends JCEKeyGenerator
+    {
+        public AES()
+        {
+            super("AES", 192, new CipherKeyGenerator());
+        }
+    }
+
+    public static class AES128
+        extends JCEKeyGenerator
+    {
+        public AES128()
+        {
+            super("AES", 128, new CipherKeyGenerator());
+        }
+    }
+
+    public static class AES192
+        extends JCEKeyGenerator
+    {
+        public AES192()
+        {
+            super("AES", 192, new CipherKeyGenerator());
+        }
+    }
+
+    public static class AES256
+        extends JCEKeyGenerator
+    {
+        public AES256()
+        {
+            super("AES", 256, new CipherKeyGenerator());
+        }
+    }
+
+    /**
+     * GOST28147
+     */
+    public static class GOST28147
+        extends JCEKeyGenerator
+    {
+        public GOST28147()
+        {
+            super("GOST28147", 256, new CipherKeyGenerator());
+        }
+    }
+    
+    /**
+     * Rijndael
+     */
+    public static class Rijndael
+        extends JCEKeyGenerator
+    {
+        public Rijndael()
+        {
+            super("Rijndael", 192, new CipherKeyGenerator());
+        }
+    }
+
+    /**
+     * Serpent
+     */
+    public static class Serpent
+        extends JCEKeyGenerator
+    {
+        public Serpent()
+        {
+            super("Serpent", 192, new CipherKeyGenerator());
+        }
+    }
+
+    /**
+     * Camellia
+     */
+    public static class Camellia
+        extends JCEKeyGenerator
+    {
+        public Camellia()
+        {
+            super("Camellia", 256, new CipherKeyGenerator());
+        }
+    }
+    
+    /**
+     * CAST5
+     */
+    public static class CAST5
+        extends JCEKeyGenerator
+    {
+        public CAST5()
+        {
+            super("CAST5", 128, new CipherKeyGenerator());
+        }
+    }
+
+    /**
+     * CAST6
+     */
+    public static class CAST6
+        extends JCEKeyGenerator
+    {
+        public CAST6()
+        {
+            super("CAST6", 256, new CipherKeyGenerator());
+        }
+    }
+
+    /**
+     * IDEA
+     */
+    public static class IDEA
+        extends JCEKeyGenerator
+    {
+        public IDEA()
+        {
+            super("IDEA", 128, new CipherKeyGenerator());
+        }
+    }
+
+    // HMAC Related secret keys..
+  
+    /**
+     * MD2HMAC
+     */
+    public static class MD2HMAC
+        extends JCEKeyGenerator
+    {
+        public MD2HMAC()
+        {
+            super("HMACMD2", 128, new CipherKeyGenerator());
+        }
+    }
+
+
+    /**
+     * MD4HMAC
+     */
+    public static class MD4HMAC
+        extends JCEKeyGenerator
+    {
+        public MD4HMAC()
+        {
+            super("HMACMD4", 128, new CipherKeyGenerator());
+        }
+    }
+
+    /**
+     * MD5HMAC
+     */
+    public static class MD5HMAC
+        extends JCEKeyGenerator
+    {
+        public MD5HMAC()
+        {
+            super("HMACMD5", 128, new CipherKeyGenerator());
+        }
+    }
+
+
+    /**
+     * RIPE128HMAC
+     */
+    public static class RIPEMD128HMAC
+        extends JCEKeyGenerator
+    {
+        public RIPEMD128HMAC()
+        {
+            super("HMACRIPEMD128", 128, new CipherKeyGenerator());
+        }
+    }
+
+    /**
+     * RIPE160HMAC
+     */
+    public static class RIPEMD160HMAC
+        extends JCEKeyGenerator
+    {
+        public RIPEMD160HMAC()
+        {
+            super("HMACRIPEMD160", 160, new CipherKeyGenerator());
+        }
+    }
+
+
+    /**
+     * HMACSHA1
+     */
+    public static class HMACSHA1
+        extends JCEKeyGenerator
+    {
+        public HMACSHA1()
+        {
+            super("HMACSHA1", 160, new CipherKeyGenerator());
+        }
+    }
+
+    /**
+     * HMACSHA224
+     */
+    public static class HMACSHA224
+        extends JCEKeyGenerator
+    {
+        public HMACSHA224()
+        {
+            super("HMACSHA224", 224, new CipherKeyGenerator());
+        }
+    }
+    
+    /**
+     * HMACSHA256
+     */
+    public static class HMACSHA256
+        extends JCEKeyGenerator
+    {
+        public HMACSHA256()
+        {
+            super("HMACSHA256", 256, new CipherKeyGenerator());
+        }
+    }
+    
+    /**
+     * HMACSHA384
+     */
+    public static class HMACSHA384
+        extends JCEKeyGenerator
+    {
+        public HMACSHA384()
+        {
+            super("HMACSHA384", 384, new CipherKeyGenerator());
+        }
+    }
+    
+    /**
+     * HMACSHA512
+     */
+    public static class HMACSHA512
+        extends JCEKeyGenerator
+    {
+        public HMACSHA512()
+        {
+            super("HMACSHA512", 512, new CipherKeyGenerator());
+        }
+    }
+    
+    /**
+     * HMACTIGER
+     */
+    public static class HMACTIGER
+        extends JCEKeyGenerator
+    {
+        public HMACTIGER()
+        {
+            super("HMACTIGER", 192, new CipherKeyGenerator());
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEMac.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEMac.java
new file mode 100644
index 0000000..74d8147
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEMac.java
@@ -0,0 +1,544 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.MacSpi;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.digests.*;
+import org.bouncycastle.crypto.engines.DESEngine;
+import org.bouncycastle.crypto.engines.DESedeEngine;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.engines.IDEAEngine;
+// import org.bouncycastle.crypto.engines.RC2Engine;
+// import org.bouncycastle.crypto.engines.RC532Engine;
+// import org.bouncycastle.crypto.engines.SkipjackEngine;
+// END android-removed
+import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
+import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.macs.GOST28147Mac;
+// END android-removed
+import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.crypto.macs.ISO9797Alg3Mac;
+import org.bouncycastle.crypto.macs.OldHMac;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+public class JCEMac
+    extends MacSpi implements PBE
+{
+    private Mac macEngine;
+
+    private int                     pbeType = PKCS12;
+    private int                     pbeHash = SHA1;
+    private int                     keySize = 160;
+
+    protected JCEMac(
+        Mac macEngine)
+    {
+        this.macEngine = macEngine;
+    }
+
+    protected JCEMac(
+        Mac macEngine,
+        int pbeType,
+        int pbeHash,
+        int keySize)
+    {
+        this.macEngine = macEngine;
+        this.pbeType = pbeType;
+        this.pbeHash = pbeHash;
+        this.keySize = keySize;
+    }
+
+    protected void engineInit(
+        Key                     key,
+        AlgorithmParameterSpec  params)
+        throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        CipherParameters        param;
+
+        if (key == null)
+        {
+            throw new InvalidKeyException("key is null");
+        }
+        
+        if (key instanceof JCEPBEKey)
+        {
+            JCEPBEKey   k = (JCEPBEKey)key;
+            
+            if (k.getParam() != null)
+            {
+                param = k.getParam();
+            }
+            else if (params instanceof PBEParameterSpec)
+            {
+                param = PBE.Util.makePBEMacParameters(k, params);
+            }
+            else
+            {
+                throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
+            }
+        }
+        else if (params instanceof IvParameterSpec)
+        {
+            param = new ParametersWithIV(new KeyParameter(key.getEncoded()), ((IvParameterSpec)params).getIV());
+        }
+        else if (params == null)
+        {
+            param = new KeyParameter(key.getEncoded());
+        }
+        else
+        {
+            throw new InvalidAlgorithmParameterException("unknown parameter type.");
+        }
+
+        macEngine.init(param);
+    }
+
+    protected int engineGetMacLength() 
+    {
+        return macEngine.getMacSize();
+    }
+
+    protected void engineReset() 
+    {
+        macEngine.reset();
+    }
+
+    protected void engineUpdate(
+        byte    input) 
+    {
+        macEngine.update(input);
+    }
+
+    protected void engineUpdate(
+        byte[]  input,
+        int     offset,
+        int     len) 
+    {
+        macEngine.update(input, offset, len);
+    }
+
+    protected byte[] engineDoFinal() 
+    {
+        byte[]  out = new byte[engineGetMacLength()];
+
+        macEngine.doFinal(out, 0);
+
+        return out;
+    }
+
+    /**
+     * the classes that extend directly off us.
+     */
+
+    /**
+     * DES
+     */
+    public static class DES
+        extends JCEMac
+    {
+        public DES()
+        {
+            super(new CBCBlockCipherMac(new DESEngine()));
+        }
+    }
+
+    /**
+     * DESede
+     */
+    public static class DESede
+        extends JCEMac
+    {
+        public DESede()
+        {
+            super(new CBCBlockCipherMac(new DESedeEngine()));
+        }
+    }
+
+    /**
+     * SKIPJACK
+     */
+    // BEGIN android-removed
+    // public static class Skipjack
+    //     extends JCEMac
+    // {
+    //     public Skipjack()
+    //     {
+    //         super(new CBCBlockCipherMac(new SkipjackEngine()));
+    //     }
+    // }
+    // END android-removed
+
+    /**
+     * IDEA
+     */
+    // BEGIN android-removed
+    // public static class IDEA
+    //     extends JCEMac
+    // {
+    //     public IDEA()
+    //     {
+    //         super(new CBCBlockCipherMac(new IDEAEngine()));
+    //     }
+    // }
+    // END android-removed
+
+    /**
+     * RC2
+     */
+    // BEGIN android-removed
+    // public static class RC2
+    //     extends JCEMac
+    // {
+    //     public RC2()
+    //     {
+    //         super(new CBCBlockCipherMac(new RC2Engine()));
+    //     }
+    // }
+    // END android-removed
+
+    /**
+     * RC5
+     */
+    // BEGIN android-removed
+    // public static class RC5
+    //     extends JCEMac
+    // {
+    //     public RC5()
+    //     {
+    //         super(new CBCBlockCipherMac(new RC532Engine()));
+    //     }
+    // }
+    // END android-removed
+
+    /**
+     * GOST28147
+     */
+    // BEGIN android-removed
+    // public static class GOST28147
+    //     extends JCEMac
+    // {
+    //     public GOST28147()
+    //     {
+    //         super(new GOST28147Mac());
+    //     }
+    // }
+    // END android-removed
+    
+    /**
+     * DES
+     */
+    public static class DESCFB8
+        extends JCEMac
+    {
+        public DESCFB8()
+        {
+            super(new CFBBlockCipherMac(new DESEngine()));
+        }
+    }
+
+    /**
+     * DESede
+     */
+    public static class DESedeCFB8
+        extends JCEMac
+    {
+        public DESedeCFB8()
+        {
+            super(new CFBBlockCipherMac(new DESedeEngine()));
+        }
+    }
+
+    /**
+     * SKIPJACK
+     */
+    // BEGIN android-removed
+    // public static class SkipjackCFB8
+    //     extends JCEMac
+    // {
+    //     public SkipjackCFB8()
+    //     {
+    //         super(new CFBBlockCipherMac(new SkipjackEngine()));
+    //     }
+    // }
+    // END android-removed
+
+    /**
+     * IDEACFB8
+     */
+    // BEGIN android-removed
+    // public static class IDEACFB8
+    //     extends JCEMac
+    // {
+    //     public IDEACFB8()
+    //     {
+    //         super(new CFBBlockCipherMac(new IDEAEngine()));
+    //     }
+    // }
+    // END android-removed
+
+    /**
+     * RC2CFB8
+     */
+    // BEGIN android-removed
+    // public static class RC2CFB8
+    //     extends JCEMac
+    // {
+    //     public RC2CFB8()
+    //     {
+    //         super(new CFBBlockCipherMac(new RC2Engine()));
+    //     }
+    // }
+    // END android-removed
+
+    /**
+     * RC5CFB8
+     */
+    // BEGIN android-removed
+    // public static class RC5CFB8
+    //     extends JCEMac
+    // {
+    //     public RC5CFB8()
+    //     {
+    //         super(new CFBBlockCipherMac(new RC532Engine()));
+    //     }
+    // }
+    // END android-removed
+    
+    
+    /**
+     * DESede64
+     */
+    public static class DESede64
+        extends JCEMac
+    {
+        public DESede64()
+        {
+            super(new CBCBlockCipherMac(new DESedeEngine(), 64));
+        }
+    }
+    
+    /**
+     * DES9797Alg3
+     */
+    public static class DES9797Alg3
+        extends JCEMac
+    {
+        public DES9797Alg3()
+        {
+            super(new ISO9797Alg3Mac(new DESEngine()));
+        }
+    }
+
+    /**
+     * MD2 HMac
+     */
+    // BEGIN android-removed
+    // public static class MD2
+    //     extends JCEMac
+    // {
+    //     public MD2()
+    //     {
+    //         super(new HMac(new MD2Digest()));
+    //     }
+    // }
+    // END android-removed
+
+    /**
+     * MD4 HMac
+     */
+    // BEGIN android-removed
+    // public static class MD4
+    //     extends JCEMac
+    // {
+    //     public MD4()
+    //     {
+    //         super(new HMac(new MD4Digest()));
+    //     }
+    // }
+    // END android-removed
+
+    /**
+     * MD5 HMac
+     */
+    public static class MD5
+        extends JCEMac
+    {
+        public MD5()
+        {
+            super(new HMac(new MD5Digest()));
+        }
+    }
+
+    /**
+     * SHA1 HMac
+     */
+    public static class SHA1
+        extends JCEMac
+    {
+        public SHA1()
+        {
+            super(new HMac(new SHA1Digest()));
+        }
+    }
+
+    /**
+     * SHA-224 HMac
+     */
+    public static class SHA224
+        extends JCEMac
+    {
+        public SHA224()
+        {
+            super(new HMac(new SHA224Digest()));
+        }
+    }
+    
+    /**
+     * SHA-256 HMac
+     */
+    public static class SHA256
+        extends JCEMac
+    {
+        public SHA256()
+        {
+            super(new HMac(new SHA256Digest()));
+        }
+    }
+
+    /**
+     * SHA-384 HMac
+     */
+    public static class SHA384
+        extends JCEMac
+    {
+        public SHA384()
+        {
+            super(new HMac(new SHA384Digest()));
+        }
+    }
+
+    public static class OldSHA384
+        extends JCEMac
+    {
+        public OldSHA384()
+        {
+            super(new OldHMac(new SHA384Digest()));
+        }
+    }
+    
+    /**
+     * SHA-512 HMac
+     */
+    public static class SHA512
+        extends JCEMac
+    {
+        public SHA512()
+        {
+            super(new HMac(new SHA512Digest()));
+        }
+    }
+
+    /**
+     * SHA-512 HMac
+     */
+    public static class OldSHA512
+        extends JCEMac
+    {
+        public OldSHA512()
+        {
+            super(new OldHMac(new SHA512Digest()));
+        }
+    }
+    
+// BEGIN android-removed
+//    /**
+//     * RIPEMD128 HMac
+//     */
+//    public static class RIPEMD128
+//        extends JCEMac
+//    {
+//        public RIPEMD128()
+//        {
+//           super(new HMac(new RIPEMD128Digest()));
+//        }
+//    }
+//
+//    /**
+//     * RIPEMD160 HMac
+//     */
+//    public static class RIPEMD160
+//        extends JCEMac
+//    {
+//        public RIPEMD160()
+//        {
+//           super(new HMac(new RIPEMD160Digest()));
+//        }
+//    }
+//
+//    /**
+//     * Tiger HMac
+//     */
+//    public static class Tiger
+//        extends JCEMac
+//    {
+//        public Tiger()
+//        {
+//            super(new HMac(new TigerDigest()));
+//        }
+//    }
+//
+//    //
+//    // PKCS12 states that the same algorithm should be used
+//    // for the key generation as is used in the HMAC, so that
+//    // is what we do here.
+//    //
+//
+//    /**
+//     * PBEWithHmacRIPEMD160
+//     */
+//    public static class PBEWithRIPEMD160
+//        extends JCEMac
+//    {
+//        public PBEWithRIPEMD160()
+//        {
+//            super(new HMac(new RIPEMD160Digest()), PKCS12, RIPEMD160, 160);
+//        }
+//    }
+// END android-removed
+
+    /**
+     * PBEWithHmacSHA
+     */
+    public static class PBEWithSHA
+        extends JCEMac
+    {
+        public PBEWithSHA()
+        {
+            super(new HMac(new SHA1Digest()), PKCS12, SHA1, 160);
+        }
+    }
+
+    /**
+     * PBEWithHmacTiger
+     */
+// BEGIN android-removed
+//    public static class PBEWithTiger
+//        extends JCEMac
+//    {
+//        public PBEWithTiger()
+//        {
+//            super(new HMac(new TigerDigest()), PKCS12, TIGER, 192);
+//        }
+//    }
+// END android-removed
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEPBEKey.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEPBEKey.java
new file mode 100644
index 0000000..13b5230
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEPBEKey.java
@@ -0,0 +1,151 @@
+package org.bouncycastle.jce.provider;
+
+import javax.crypto.interfaces.PBEKey;
+import javax.crypto.spec.PBEKeySpec;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.PBEParametersGenerator;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+public class JCEPBEKey
+    implements PBEKey
+{
+    String              algorithm;
+    DERObjectIdentifier oid;
+    int                 type;
+    int                 digest;
+    int                 keySize;
+    int                 ivSize;
+    CipherParameters    param;
+    PBEKeySpec          pbeKeySpec;
+    boolean             tryWrong = false;
+
+    /**
+     * @param param
+     */
+    public JCEPBEKey(
+        String              algorithm,
+        DERObjectIdentifier oid,
+        int                 type,
+        int                 digest,
+        int                 keySize,
+        int                 ivSize,
+        PBEKeySpec          pbeKeySpec,
+        CipherParameters    param)
+    {
+        this.algorithm = algorithm;
+        this.oid = oid;
+        this.type = type;
+        this.digest = digest;
+        this.keySize = keySize;
+        this.ivSize = ivSize;
+        this.pbeKeySpec = pbeKeySpec;
+        this.param = param;
+    }
+
+    public String getAlgorithm()
+    {
+        return algorithm;
+    }
+
+    public String getFormat()
+    {
+        return "RAW";
+    }
+
+    public byte[] getEncoded()
+    {
+        if (param != null)
+        {
+            KeyParameter    kParam;
+            
+            if (param instanceof ParametersWithIV)
+            {
+                kParam = (KeyParameter)((ParametersWithIV)param).getParameters();
+            }
+            else
+            {
+                kParam = (KeyParameter)param;
+            }
+            
+            return kParam.getKey();
+        }
+        else
+        {
+            if (type == PBE.PKCS12)
+            {
+                return PBEParametersGenerator.PKCS12PasswordToBytes(pbeKeySpec.getPassword());
+            }
+            else
+            {   
+                return PBEParametersGenerator.PKCS5PasswordToBytes(pbeKeySpec.getPassword());
+            }
+        }
+    }
+    
+    int getType()
+    {
+        return type;
+    }
+    
+    int getDigest()
+    {
+        return digest;
+    }
+    
+    int getKeySize()
+    {
+        return keySize;
+    }
+    
+    int getIvSize()
+    {
+        return ivSize;
+    }
+    
+    CipherParameters getParam()
+    {
+        return param;
+    }
+
+    /* (non-Javadoc)
+     * @see javax.crypto.interfaces.PBEKey#getPassword()
+     */
+    public char[] getPassword()
+    {
+        return pbeKeySpec.getPassword();
+    }
+
+    /* (non-Javadoc)
+     * @see javax.crypto.interfaces.PBEKey#getSalt()
+     */
+    public byte[] getSalt()
+    {
+        return pbeKeySpec.getSalt();
+    }
+
+    /* (non-Javadoc)
+     * @see javax.crypto.interfaces.PBEKey#getIterationCount()
+     */
+    public int getIterationCount()
+    {
+        return pbeKeySpec.getIterationCount();
+    }
+    
+    public DERObjectIdentifier getOID()
+    {
+        return oid;
+    }
+    
+    void setTryWrongPKCS12Zero(boolean tryWrong)
+    {
+        this.tryWrong = tryWrong; 
+    }
+    
+    boolean shouldTryWrongPKCS12()
+    {
+        return tryWrong;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCERSACipher.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCERSACipher.java
new file mode 100644
index 0000000..54b49c0
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCERSACipher.java
@@ -0,0 +1,581 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.MGF1ParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
+
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.encodings.ISO9796d1Encoding;
+import org.bouncycastle.crypto.encodings.OAEPEncoding;
+import org.bouncycastle.crypto.encodings.PKCS1Encoding;
+import org.bouncycastle.crypto.engines.RSAEngine;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.util.Strings;
+
+public class JCERSACipher extends WrapCipherSpi
+{
+    private AsymmetricBlockCipher   cipher;
+    private AlgorithmParameterSpec  paramSpec;
+    private AlgorithmParameters     engineParams;
+    private boolean                 publicKeyOnly = false;
+    private boolean                 privateKeyOnly = false;
+    private ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+
+    public JCERSACipher(
+        AsymmetricBlockCipher   engine)
+    {
+        cipher = engine;
+    }
+
+    public JCERSACipher(
+        OAEPParameterSpec  pSpec)
+    {
+        try
+        {
+            initFromSpec(pSpec);
+        }
+        catch (NoSuchPaddingException e)
+        {
+            throw new IllegalArgumentException(e.getMessage());
+        }
+    }
+
+    public JCERSACipher(
+        boolean                 publicKeyOnly,
+        boolean                 privateKeyOnly,
+        AsymmetricBlockCipher   engine)
+    {
+        this.publicKeyOnly = publicKeyOnly;
+        this.privateKeyOnly = privateKeyOnly;
+        cipher = engine;
+    }
+     
+    private void initFromSpec(
+        OAEPParameterSpec pSpec) 
+        throws NoSuchPaddingException
+    {
+        MGF1ParameterSpec   mgfParams = (MGF1ParameterSpec)pSpec.getMGFParameters();
+        Digest              digest = JCEDigestUtil.getDigest(mgfParams.getDigestAlgorithm());
+        
+        if (digest == null)
+        {
+            throw new NoSuchPaddingException("no match on OAEP constructor for digest algorithm: "+ mgfParams.getDigestAlgorithm());
+        }
+
+        cipher = new OAEPEncoding(new RSAEngine(), digest, ((PSource.PSpecified)pSpec.getPSource()).getValue());        
+        paramSpec = pSpec;
+    }
+    
+    protected int engineGetBlockSize() 
+    {
+        try
+        {
+            return cipher.getInputBlockSize();
+        }
+        catch (NullPointerException e)
+        {
+            throw new IllegalStateException("RSA Cipher not initialised");
+        }
+    }
+
+    protected byte[] engineGetIV() 
+    {
+        return null;
+    }
+
+    protected int engineGetKeySize(
+        Key     key) 
+    {
+        if (key instanceof RSAPrivateKey)
+        {
+            RSAPrivateKey   k = (RSAPrivateKey)key;
+
+            return k.getModulus().bitLength();
+        }
+        else if (key instanceof RSAPublicKey)
+        {
+            RSAPublicKey   k = (RSAPublicKey)key;
+
+            return k.getModulus().bitLength();
+        }
+
+        throw new IllegalArgumentException("not an RSA key!");
+    }
+
+    protected int engineGetOutputSize(
+        int     inputLen) 
+    {
+        try
+        {
+            return cipher.getOutputBlockSize();
+        }
+        catch (NullPointerException e)
+        {
+            throw new IllegalStateException("RSA Cipher not initialised");
+        }
+    }
+
+    protected AlgorithmParameters engineGetParameters() 
+    {
+        if (engineParams == null)
+        {
+            if (paramSpec != null)
+            {
+                try
+                {
+                    engineParams = AlgorithmParameters.getInstance("OAEP", "BC");
+                    engineParams.init(paramSpec);
+                }
+                catch (Exception e)
+                {
+                    throw new RuntimeException(e.toString());
+                }
+            }
+        }
+
+        return engineParams;
+    }
+
+    protected void engineSetMode(
+        String  mode)
+        throws NoSuchAlgorithmException
+    {
+        String md = Strings.toUpperCase(mode);
+        
+        if (md.equals("NONE") || md.equals("ECB"))
+        {
+            return;
+        }
+        
+        if (md.equals("1"))
+        {
+            privateKeyOnly = true;
+            publicKeyOnly = false;
+            return;
+        }
+        else if (md.equals("2"))
+        {
+            privateKeyOnly = false;
+            publicKeyOnly = true;
+            return;
+        }
+        
+        throw new NoSuchAlgorithmException("can't support mode " + mode);
+    }
+
+    protected void engineSetPadding(
+        String  padding) 
+        throws NoSuchPaddingException
+    {
+        String pad = Strings.toUpperCase(padding);
+
+        if (pad.equals("NOPADDING"))
+        {
+            cipher = new RSAEngine();
+        }
+        else if (pad.equals("PKCS1PADDING"))
+        {
+            cipher = new PKCS1Encoding(new RSAEngine());
+        }
+        else if (pad.equals("ISO9796-1PADDING"))
+        {
+            cipher = new ISO9796d1Encoding(new RSAEngine());
+        }
+        else if (pad.equals("OAEPWITHMD5ANDMGF1PADDING"))
+        {
+            initFromSpec(new OAEPParameterSpec("MD5", "MGF1", new MGF1ParameterSpec("MD5"), PSource.PSpecified.DEFAULT));
+        }
+        else if (pad.equals("OAEPPADDING"))
+        {
+            initFromSpec(OAEPParameterSpec.DEFAULT);
+        }
+        else if (pad.equals("OAEPWITHSHA1ANDMGF1PADDING"))
+        {
+            initFromSpec(OAEPParameterSpec.DEFAULT);
+        }
+        else if (pad.equals("OAEPWITHSHA224ANDMGF1PADDING"))
+        {
+            initFromSpec(new OAEPParameterSpec("SHA-224", "MGF1", new MGF1ParameterSpec("SHA-224"), PSource.PSpecified.DEFAULT));
+        }
+        else if (pad.equals("OAEPWITHSHA256ANDMGF1PADDING"))
+        {
+            initFromSpec(new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
+        }
+        else if (pad.equals("OAEPWITHSHA384ANDMGF1PADDING"))
+        {
+            initFromSpec(new OAEPParameterSpec("SHA-384", "MGF1", MGF1ParameterSpec.SHA384, PSource.PSpecified.DEFAULT));
+        }
+        else if (pad.equals("OAEPWITHSHA512ANDMGF1PADDING"))
+        {
+            initFromSpec(new OAEPParameterSpec("SHA-512", "MGF1", MGF1ParameterSpec.SHA512, PSource.PSpecified.DEFAULT));
+        }
+        else
+        {
+            throw new NoSuchPaddingException(padding + " unavailable with RSA.");
+        }
+    }
+
+    protected void engineInit(
+        int                     opmode,
+        Key                     key,
+        AlgorithmParameterSpec  params,
+        SecureRandom            random) 
+    throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        CipherParameters        param;
+
+        if (params == null || params instanceof OAEPParameterSpec)
+        {
+            if (key instanceof RSAPublicKey)
+            {
+                if (privateKeyOnly)
+                {
+                    throw new InvalidKeyException(
+                                "mode 1 requires RSAPrivateKey");
+                }
+
+                param = RSAUtil.generatePublicKeyParameter((RSAPublicKey)key);
+            }
+            else if (key instanceof RSAPrivateKey)
+            {
+                if (publicKeyOnly)
+                {
+                    throw new InvalidKeyException(
+                                "mode 2 requires RSAPublicKey");
+                }
+
+                param = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)key);
+            }
+            else
+            {
+                throw new InvalidKeyException("unknown key type passed to RSA");
+            }
+            
+            if (params != null)
+            {
+                OAEPParameterSpec   spec = (OAEPParameterSpec)params;
+                
+                paramSpec = params;
+                
+                if (!spec.getMGFAlgorithm().equalsIgnoreCase("MGF1") && !spec.getMGFAlgorithm().equals(PKCSObjectIdentifiers.id_mgf1.getId()))
+                {
+                    throw new InvalidAlgorithmParameterException("unknown mask generation function specified");
+                }
+                
+                if (!(spec.getMGFParameters() instanceof MGF1ParameterSpec))
+                {
+                    throw new InvalidAlgorithmParameterException("unkown MGF parameters");
+                }
+                
+                MGF1ParameterSpec   mgfParams = (MGF1ParameterSpec)spec.getMGFParameters();
+                
+                if (!JCEDigestUtil.isSameDigest(mgfParams.getDigestAlgorithm(), spec.getDigestAlgorithm()))
+                {
+                    throw new InvalidAlgorithmParameterException("digest algorithm for MGF should be the same as for OAEP parameters.");
+                }
+                
+                Digest              digest = JCEDigestUtil.getDigest(mgfParams.getDigestAlgorithm());
+                
+                if (digest == null)
+                {
+                    throw new InvalidAlgorithmParameterException("no match on MGF digest algorithm: "+ mgfParams.getDigestAlgorithm());
+                }
+                
+                cipher = new OAEPEncoding(new RSAEngine(), digest, ((PSource.PSpecified)spec.getPSource()).getValue());
+            }
+        }
+        else
+        {
+            throw new IllegalArgumentException("unknown parameter type.");
+        }
+
+        if (!(cipher instanceof RSAEngine))
+        {
+            if (random != null)
+            {
+                param = new ParametersWithRandom(param, random);
+            }
+            else
+            {
+                param = new ParametersWithRandom(param, new SecureRandom());
+            }
+        }
+
+        switch (opmode)
+        {
+        case Cipher.ENCRYPT_MODE:
+        case Cipher.WRAP_MODE:
+            cipher.init(true, param);
+            break;
+        case Cipher.DECRYPT_MODE:
+        case Cipher.UNWRAP_MODE:
+            cipher.init(false, param);
+            break;
+        default:
+            throw new InvalidParameterException("unknown opmode " + opmode + " passed to RSA");
+        }
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key                 key,
+        AlgorithmParameters params,
+        SecureRandom        random) 
+    throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        AlgorithmParameterSpec  paramSpec = null;
+
+        if (params != null)
+        {
+            try
+            {
+                paramSpec = params.getParameterSpec(OAEPParameterSpec.class);
+            }
+            catch (InvalidParameterSpecException e)
+            {
+                throw new InvalidAlgorithmParameterException("cannot recognise parameters: " + e.toString(), e);
+            }
+        }
+
+        engineParams = params;
+        engineInit(opmode, key, paramSpec, random);
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key                 key,
+        SecureRandom        random) 
+    throws InvalidKeyException
+    {
+        try
+        {
+            engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+        }
+        catch (InvalidAlgorithmParameterException e)
+        {
+            // this shouldn't happen
+            throw new RuntimeException("Eeeek! " + e.toString(), e);
+        }
+    }
+
+    protected byte[] engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen) 
+    {
+        bOut.write(input, inputOffset, inputLen);
+
+        if (cipher instanceof RSAEngine)
+        {
+            if (bOut.size() > cipher.getInputBlockSize() + 1)
+            {
+                throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+            }
+        }
+        else
+        {
+            if (bOut.size() > cipher.getInputBlockSize())
+            {
+                throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+            }
+        }
+
+        return null;
+    }
+
+    protected int engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset) 
+    {
+        bOut.write(input, inputOffset, inputLen);
+
+        if (cipher instanceof RSAEngine)
+        {
+            if (bOut.size() > cipher.getInputBlockSize() + 1)
+            {
+                throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+            }
+        }
+        else
+        {
+            if (bOut.size() > cipher.getInputBlockSize())
+            {
+                throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+            }
+        }
+
+        return 0;
+    }
+
+    protected byte[] engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen) 
+        throws IllegalBlockSizeException, BadPaddingException
+    {
+        if (input != null)
+        {
+            bOut.write(input, inputOffset, inputLen);
+        }
+
+        if (cipher instanceof RSAEngine)
+        {
+            if (bOut.size() > cipher.getInputBlockSize() + 1)
+            {
+                throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+            }
+        }
+        else
+        {
+            if (bOut.size() > cipher.getInputBlockSize())
+            {
+                throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+            }
+        }
+
+        try
+        {
+            byte[]  bytes = bOut.toByteArray();
+
+            bOut.reset();
+
+            return cipher.processBlock(bytes, 0, bytes.length);
+        }
+        catch (InvalidCipherTextException e)
+        {
+            throw new BadPaddingException(e.getMessage());
+        }
+    }
+
+    protected int engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset) 
+        throws IllegalBlockSizeException, BadPaddingException
+    {
+        if (input != null)
+        {
+            bOut.write(input, inputOffset, inputLen);
+        }
+
+        if (cipher instanceof RSAEngine)
+        {
+            if (bOut.size() > cipher.getInputBlockSize() + 1)
+            {
+                throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+            }
+        }
+        else
+        {
+            if (bOut.size() > cipher.getInputBlockSize())
+            {
+                throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+            }
+        }
+
+        byte[]  out;
+
+        try
+        {
+            byte[]  bytes = bOut.toByteArray();
+            bOut.reset();
+
+            out = cipher.processBlock(bytes, 0, bytes.length);
+        }
+        catch (InvalidCipherTextException e)
+        {
+            throw new BadPaddingException(e.getMessage());
+        }
+
+        for (int i = 0; i != out.length; i++)
+        {
+            output[outputOffset + i] = out[i];
+        }
+
+        return out.length;
+    }
+
+    /**
+     * classes that inherit from us.
+     */
+
+    static public class NoPadding
+        extends JCERSACipher
+    {
+        public NoPadding()
+        {
+            super(new RSAEngine());
+        }
+    }
+
+    static public class PKCS1v1_5Padding
+        extends JCERSACipher
+    {
+        public PKCS1v1_5Padding()
+        {
+            super(new PKCS1Encoding(new RSAEngine()));
+        }
+    }
+
+    static public class PKCS1v1_5Padding_PrivateOnly
+        extends JCERSACipher
+    {
+        public PKCS1v1_5Padding_PrivateOnly()
+        {
+            super(false, true, new PKCS1Encoding(new RSAEngine()));
+        }
+    }
+
+    static public class PKCS1v1_5Padding_PublicOnly
+        extends JCERSACipher
+    {
+        public PKCS1v1_5Padding_PublicOnly()
+        {
+            super(true, false, new PKCS1Encoding(new RSAEngine()));
+        }
+    }
+
+    static public class OAEPPadding
+        extends JCERSACipher
+    {
+        public OAEPPadding()
+        {
+            super(OAEPParameterSpec.DEFAULT);
+        }
+    }
+    
+    static public class ISO9796d1Padding
+        extends JCERSACipher
+    {
+        public ISO9796d1Padding()
+        {
+            super(new ISO9796d1Encoding(new RSAEngine()));
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java
new file mode 100644
index 0000000..0971e90
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java
@@ -0,0 +1,237 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.spec.RSAPrivateCrtKeySpec;
+
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+
+/**
+ * A provider representation for a RSA private key, with CRT factors included.
+ */
+public class JCERSAPrivateCrtKey
+    extends JCERSAPrivateKey
+    implements RSAPrivateCrtKey
+{
+    private BigInteger  publicExponent;
+    private BigInteger  primeP;
+    private BigInteger  primeQ;
+    private BigInteger  primeExponentP;
+    private BigInteger  primeExponentQ;
+    private BigInteger  crtCoefficient;
+
+    /**
+     * construct a private key from it's org.bouncycastle.crypto equivalent.
+     *
+     * @param key the parameters object representing the private key.
+     */
+    JCERSAPrivateCrtKey(
+        RSAPrivateCrtKeyParameters key)
+    {
+        super(key);
+
+        this.publicExponent = key.getPublicExponent();
+        this.primeP = key.getP();
+        this.primeQ = key.getQ();
+        this.primeExponentP = key.getDP();
+        this.primeExponentQ = key.getDQ();
+        this.crtCoefficient = key.getQInv();
+    }
+
+    /**
+     * construct a private key from an RSAPrivateCrtKeySpec
+     *
+     * @param spec the spec to be used in construction.
+     */
+    JCERSAPrivateCrtKey(
+        RSAPrivateCrtKeySpec spec)
+    {
+        this.modulus = spec.getModulus();
+        this.publicExponent = spec.getPublicExponent();
+        this.privateExponent = spec.getPrivateExponent();
+        this.primeP = spec.getPrimeP();
+        this.primeQ = spec.getPrimeQ();
+        this.primeExponentP = spec.getPrimeExponentP();
+        this.primeExponentQ = spec.getPrimeExponentQ();
+        this.crtCoefficient = spec.getCrtCoefficient();
+    }
+
+    /**
+     * construct a private key from another RSAPrivateCrtKey.
+     *
+     * @param key the object implementing the RSAPrivateCrtKey interface.
+     */
+    JCERSAPrivateCrtKey(
+        RSAPrivateCrtKey key)
+    {
+        this.modulus = key.getModulus();
+        this.publicExponent = key.getPublicExponent();
+        this.privateExponent = key.getPrivateExponent();
+        this.primeP = key.getPrimeP();
+        this.primeQ = key.getPrimeQ();
+        this.primeExponentP = key.getPrimeExponentP();
+        this.primeExponentQ = key.getPrimeExponentQ();
+        this.crtCoefficient = key.getCrtCoefficient();
+    }
+
+    /**
+     * construct an RSA key from a private key info object.
+     */
+    JCERSAPrivateCrtKey(
+        PrivateKeyInfo  info)
+    {
+        this(new RSAPrivateKeyStructure((ASN1Sequence)info.getPrivateKey()));
+    }
+
+    /**
+     * construct an RSA key from a ASN.1 RSA private key object.
+     */
+    JCERSAPrivateCrtKey(
+        RSAPrivateKeyStructure  key)
+    {
+        this.modulus = key.getModulus();
+        this.publicExponent = key.getPublicExponent();
+        this.privateExponent = key.getPrivateExponent();
+        this.primeP = key.getPrime1();
+        this.primeQ = key.getPrime2();
+        this.primeExponentP = key.getExponent1();
+        this.primeExponentQ = key.getExponent2();
+        this.crtCoefficient = key.getCoefficient();
+    }
+
+    /**
+     * return the encoding format we produce in getEncoded().
+     *
+     * @return the encoding format we produce in getEncoded().
+     */
+    public String getFormat()
+    {
+        return "PKCS#8";
+    }
+
+    /**
+     * Return a PKCS8 representation of the key. The sequence returned
+     * represents a full PrivateKeyInfo object.
+     *
+     * @return a PKCS8 representation of the key.
+     */
+    public byte[] getEncoded()
+    {
+        // BEGIN android-changed
+        PrivateKeyInfo          info = new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.THE_ONE), new RSAPrivateKeyStructure(getModulus(), getPublicExponent(), getPrivateExponent(), getPrimeP(), getPrimeQ(), getPrimeExponentP(), getPrimeExponentQ(), getCrtCoefficient()).getDERObject());
+        // END android-changed
+
+        return info.getDEREncoded();
+    }
+
+    /**
+     * return the public exponent.
+     *
+     * @return the public exponent.
+     */
+    public BigInteger getPublicExponent()
+    {
+        return publicExponent;
+    }
+
+    /**
+     * return the prime P.
+     *
+     * @return the prime P.
+     */
+    public BigInteger getPrimeP()
+    {
+        return primeP;
+    }
+
+    /**
+     * return the prime Q.
+     *
+     * @return the prime Q.
+     */
+    public BigInteger getPrimeQ()
+    {
+        return primeQ;
+    }
+
+    /**
+     * return the prime exponent for P.
+     *
+     * @return the prime exponent for P.
+     */
+    public BigInteger getPrimeExponentP()
+    {
+        return primeExponentP;
+    }
+
+    /**
+     * return the prime exponent for Q.
+     *
+     * @return the prime exponent for Q.
+     */
+    public BigInteger getPrimeExponentQ()
+    {
+        return primeExponentQ;
+    }
+
+    /**
+     * return the CRT coefficient.
+     *
+     * @return the CRT coefficient.
+     */
+    public BigInteger getCrtCoefficient()
+    {
+        return crtCoefficient;
+    }
+
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof RSAPrivateCrtKey))
+        {
+            return false;
+        }
+
+        if (o == this)
+        {
+            return true;
+        }
+
+        RSAPrivateCrtKey key = (RSAPrivateCrtKey)o;
+
+        return this.getModulus().equals(key.getModulus())
+         && this.getPublicExponent().equals(key.getPublicExponent())
+         && this.getPrivateExponent().equals(key.getPrivateExponent())
+         && this.getPrimeP().equals(key.getPrimeP())
+         && this.getPrimeQ().equals(key.getPrimeQ())
+         && this.getPrimeExponentP().equals(key.getPrimeExponentP())
+         && this.getPrimeExponentQ().equals(key.getPrimeExponentQ())
+         && this.getCrtCoefficient().equals(key.getCrtCoefficient());
+    }
+
+    public String toString()
+    {
+        StringBuffer    buf = new StringBuffer();
+        String          nl = System.getProperty("line.separator");
+
+        buf.append("RSA Private CRT Key").append(nl);
+        buf.append("            modulus: ").append(this.getModulus().toString(16)).append(nl);
+        buf.append("    public exponent: ").append(this.getPublicExponent().toString(16)).append(nl);
+        buf.append("   private exponent: ").append(this.getPrivateExponent().toString(16)).append(nl);
+        buf.append("             primeP: ").append(this.getPrimeP().toString(16)).append(nl);
+        buf.append("             primeQ: ").append(this.getPrimeQ().toString(16)).append(nl);
+        buf.append("     primeExponentP: ").append(this.getPrimeExponentP().toString(16)).append(nl);
+        buf.append("     primeExponentQ: ").append(this.getPrimeExponentQ().toString(16)).append(nl);
+        buf.append("     crtCoefficient: ").append(this.getCrtCoefficient().toString(16)).append(nl);
+
+        return buf.toString();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateKey.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateKey.java
new file mode 100644
index 0000000..74b8d08
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateKey.java
@@ -0,0 +1,184 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.spec.RSAPrivateKeySpec;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1OutputStream;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+public class JCERSAPrivateKey
+    implements RSAPrivateKey, PKCS12BagAttributeCarrier
+{
+    protected BigInteger modulus;
+    protected BigInteger privateExponent;
+
+    private Hashtable   pkcs12Attributes = new Hashtable();
+    private Vector      pkcs12Ordering = new Vector();
+
+    protected JCERSAPrivateKey()
+    {
+    }
+
+    JCERSAPrivateKey(
+        RSAKeyParameters key)
+    {
+        this.modulus = key.getModulus();
+        this.privateExponent = key.getExponent();
+    }
+
+    JCERSAPrivateKey(
+        RSAPrivateKeySpec spec)
+    {
+        this.modulus = spec.getModulus();
+        this.privateExponent = spec.getPrivateExponent();
+    }
+
+    JCERSAPrivateKey(
+        RSAPrivateKey key)
+    {
+        this.modulus = key.getModulus();
+        this.privateExponent = key.getPrivateExponent();
+    }
+
+    public BigInteger getModulus()
+    {
+        return modulus;
+    }
+
+    public BigInteger getPrivateExponent()
+    {
+        return privateExponent;
+    }
+
+    public String getAlgorithm()
+    {
+        return "RSA";
+    }
+
+    public String getFormat()
+    {
+        return "NULL";
+    }
+
+    public byte[] getEncoded()
+    {
+        return null;
+    }
+
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof RSAPrivateKey))
+        {
+            return false;
+        }
+
+        if (o == this)
+        {
+            return true;
+        }
+
+        RSAPrivateKey key = (RSAPrivateKey)o;
+
+        return getModulus().equals(key.getModulus())
+            && getPrivateExponent().equals(key.getPrivateExponent());
+    }
+
+    public int hashCode()
+    {
+        return getModulus().hashCode() ^ getPrivateExponent().hashCode();
+    }
+
+    public void setBagAttribute(
+        DERObjectIdentifier oid,
+        DEREncodable        attribute)
+    {
+        pkcs12Attributes.put(oid, attribute);
+        pkcs12Ordering.addElement(oid);
+    }
+
+    public DEREncodable getBagAttribute(
+        DERObjectIdentifier oid)
+    {
+        return (DEREncodable)pkcs12Attributes.get(oid);
+    }
+
+    public Enumeration getBagAttributeKeys()
+    {
+        return pkcs12Ordering.elements();
+    }
+
+    private void readObject(
+        ObjectInputStream   in)
+        throws IOException, ClassNotFoundException
+    {
+        this.modulus = (BigInteger)in.readObject();
+
+        Object  obj = in.readObject();
+
+        if (obj instanceof Hashtable)
+        {
+            this.pkcs12Attributes = (Hashtable)obj;
+            this.pkcs12Ordering = (Vector)in.readObject();
+        }
+        else
+        {
+            this.pkcs12Attributes = new Hashtable();
+            this.pkcs12Ordering = new Vector();
+
+            ASN1InputStream         aIn = new ASN1InputStream((byte[])obj);
+
+            DERObjectIdentifier    oid;
+
+            while ((oid = (DERObjectIdentifier)aIn.readObject()) != null)
+            {
+                this.setBagAttribute(oid, aIn.readObject());
+            }
+        }
+
+        this.privateExponent = (BigInteger)in.readObject();
+    }
+
+    private void writeObject(
+        ObjectOutputStream  out)
+        throws IOException
+    {
+        out.writeObject(modulus);
+
+        if (pkcs12Ordering.size() == 0)
+        {
+            out.writeObject(pkcs12Attributes);
+            out.writeObject(pkcs12Ordering);
+        }
+        else
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
+
+            Enumeration             e = this.getBagAttributeKeys();
+
+            while (e.hasMoreElements())
+            {
+                DEREncodable    oid = (DEREncodable)e.nextElement();
+
+                aOut.writeObject(oid);
+                aOut.writeObject(pkcs12Attributes.get(oid));
+            }
+
+            out.writeObject(bOut.toByteArray());
+        }
+
+        out.writeObject(privateExponent);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCERSAPublicKey.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCERSAPublicKey.java
new file mode 100644
index 0000000..e546323
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCERSAPublicKey.java
@@ -0,0 +1,129 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.RSAPublicKeySpec;
+
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.RSAPublicKeyStructure;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+
+public class JCERSAPublicKey
+    implements RSAPublicKey
+{
+    private BigInteger modulus;
+    private BigInteger publicExponent;
+
+    JCERSAPublicKey(
+        RSAKeyParameters key)
+    {
+        this.modulus = key.getModulus();
+        this.publicExponent = key.getExponent();
+    }
+
+    JCERSAPublicKey(
+        RSAPublicKeySpec spec)
+    {
+        this.modulus = spec.getModulus();
+        this.publicExponent = spec.getPublicExponent();
+    }
+
+    JCERSAPublicKey(
+        RSAPublicKey key)
+    {
+        this.modulus = key.getModulus();
+        this.publicExponent = key.getPublicExponent();
+    }
+
+    JCERSAPublicKey(
+        SubjectPublicKeyInfo    info)
+    {
+        try
+        {
+            RSAPublicKeyStructure   pubKey = new RSAPublicKeyStructure((ASN1Sequence)info.getPublicKey());
+
+            this.modulus = pubKey.getModulus();
+            this.publicExponent = pubKey.getPublicExponent();
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("invalid info structure in RSA public key");
+        }
+    }
+
+    /**
+     * return the modulus.
+     *
+     * @return the modulus.
+     */
+    public BigInteger getModulus()
+    {
+        return modulus;
+    }
+
+    /**
+     * return the public exponent.
+     *
+     * @return the public exponent.
+     */
+    public BigInteger getPublicExponent()
+    {
+        return publicExponent;
+    }
+
+    public String getAlgorithm()
+    {
+        return "RSA";
+    }
+
+    public String getFormat()
+    {
+        return "X.509";
+    }
+
+    public byte[] getEncoded()
+    {
+        // BEGIN android-changed
+        SubjectPublicKeyInfo    info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.THE_ONE), new RSAPublicKeyStructure(getModulus(), getPublicExponent()).getDERObject());
+        // END android-changed
+
+        return info.getDEREncoded();
+    }
+
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof RSAPublicKey))
+        {
+            return false;
+        }
+
+        if (o == this)
+        {
+            return true;
+        }
+
+        RSAPublicKey key = (RSAPublicKey)o;
+
+        return getModulus().equals(key.getModulus())
+            && getPublicExponent().equals(key.getPublicExponent());
+    }
+
+    public String toString()
+    {
+        StringBuffer    buf = new StringBuffer();
+        String          nl = System.getProperty("line.separator");
+
+        buf.append("RSA Public Key").append(nl);
+        buf.append("            modulus: ").append(this.getModulus().toString(16)).append(nl);
+        buf.append("    public exponent: ").append(this.getPublicExponent().toString(16)).append(nl);
+
+        return buf.toString();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCESecretKeyFactory.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCESecretKeyFactory.java
new file mode 100644
index 0000000..7892c3f
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCESecretKeyFactory.java
@@ -0,0 +1,611 @@
+package org.bouncycastle.jce.provider;
+
+import java.lang.reflect.Constructor;
+import java.security.InvalidKeyException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactorySpi;
+import javax.crypto.spec.DESKeySpec;
+import javax.crypto.spec.DESedeKeySpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.params.DESParameters;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+public class JCESecretKeyFactory
+    extends SecretKeyFactorySpi
+    implements PBE
+{
+    protected String                algName;
+    protected DERObjectIdentifier   algOid;
+
+    protected JCESecretKeyFactory(
+        String               algName,
+        DERObjectIdentifier  algOid)
+    {
+        this.algName = algName;
+        this.algOid = algOid;
+    }
+
+    protected SecretKey engineGenerateSecret(
+        KeySpec keySpec)
+    throws InvalidKeySpecException
+    {
+        if (keySpec instanceof SecretKeySpec)
+        {
+            return (SecretKey)keySpec;
+        }
+
+        throw new InvalidKeySpecException("Invalid KeySpec");
+    }
+
+    protected KeySpec engineGetKeySpec(
+        SecretKey key,
+        Class keySpec)
+    throws InvalidKeySpecException
+    {
+        if (keySpec == null)
+        {
+            throw new InvalidKeySpecException("keySpec parameter is null");
+        }
+        if (key == null)
+        {
+            throw new InvalidKeySpecException("key parameter is null");
+        }
+        
+        if (SecretKeySpec.class.isAssignableFrom(keySpec))
+        {
+            return new SecretKeySpec(key.getEncoded(), algName);
+        }
+
+        try
+        {
+            Class[] parameters = { byte[].class };
+
+            Constructor c = keySpec.getConstructor(parameters);
+            Object[]    p = new Object[1];
+
+            p[0] = key.getEncoded();
+
+            return (KeySpec)c.newInstance(p);
+        }
+        catch (Exception e)
+        {
+            throw new InvalidKeySpecException(e.toString());
+        }
+    }
+
+    protected SecretKey engineTranslateKey(
+        SecretKey key)
+    throws InvalidKeyException
+    {
+        if (key == null)
+        {
+            throw new InvalidKeyException("key parameter is null");
+        }
+        
+        if (!key.getAlgorithm().equalsIgnoreCase(algName))
+        {
+            throw new InvalidKeyException("Key not of type " + algName + ".");
+        }
+
+        return new SecretKeySpec(key.getEncoded(), algName);
+    }
+
+    /*
+     * classes that inherit from us
+     */
+    
+    static public class PBEKeyFactory
+        extends JCESecretKeyFactory
+    {
+        private boolean forCipher;
+        private int     scheme;
+        private int     digest;
+        private int     keySize;
+        private int     ivSize;
+        
+        public PBEKeyFactory(
+            String              algorithm,
+            DERObjectIdentifier oid,
+            boolean             forCipher,
+            int                 scheme,
+            int                 digest,
+            int                 keySize,
+            int                 ivSize)
+        {
+            super(algorithm, oid);
+            
+            this.forCipher = forCipher;
+            this.scheme = scheme;
+            this.digest = digest;
+            this.keySize = keySize;
+            this.ivSize = ivSize;
+        }
+    
+        protected SecretKey engineGenerateSecret(
+            KeySpec keySpec)
+            throws InvalidKeySpecException
+        {
+            if (keySpec instanceof PBEKeySpec)
+            {
+                PBEKeySpec          pbeSpec = (PBEKeySpec)keySpec;
+                CipherParameters    param;
+                
+                if (pbeSpec.getSalt() == null)
+                {
+                    return new JCEPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null);
+                }
+                
+                if (forCipher)
+                {
+                    param = Util.makePBEParameters(pbeSpec, scheme, digest, keySize, ivSize);
+                }
+                else
+                {
+                    param = Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
+                }
+                
+                return new JCEPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
+            }
+            
+            throw new InvalidKeySpecException("Invalid KeySpec");
+        }
+    }
+
+    static public class DESPBEKeyFactory
+        extends JCESecretKeyFactory
+    {
+        private boolean forCipher;
+        private int     scheme;
+        private int     digest;
+        private int     keySize;
+        private int     ivSize;
+        
+        public DESPBEKeyFactory(
+            String              algorithm,
+            DERObjectIdentifier oid,
+            boolean             forCipher,
+            int                 scheme,
+            int                 digest,
+            int                 keySize,
+            int                 ivSize)
+        {
+            super(algorithm, oid);
+            
+            this.forCipher = forCipher;
+            this.scheme = scheme;
+            this.digest = digest;
+            this.keySize = keySize;
+            this.ivSize = ivSize;
+        }
+    
+        protected SecretKey engineGenerateSecret(
+            KeySpec keySpec)
+        throws InvalidKeySpecException
+        {
+            if (keySpec instanceof PBEKeySpec)
+            {
+                PBEKeySpec pbeSpec = (PBEKeySpec)keySpec;
+                CipherParameters    param;
+                
+                if (pbeSpec.getSalt() == null)
+                {
+                    return new JCEPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null);
+                }
+                
+                if (forCipher)
+                {
+                    param = Util.makePBEParameters(pbeSpec, scheme, digest, keySize, ivSize);
+                }
+                else
+                {
+                    param = Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
+                }
+                
+                if (param instanceof ParametersWithIV)
+                {
+                    KeyParameter    kParam = (KeyParameter)((ParametersWithIV)param).getParameters();
+
+                    DESParameters.setOddParity(kParam.getKey());
+                }
+                else
+                {
+                    KeyParameter    kParam = (KeyParameter)param;
+
+                    DESParameters.setOddParity(kParam.getKey());
+                }
+                
+                return new JCEPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
+            }
+            
+            throw new InvalidKeySpecException("Invalid KeySpec");
+        }
+    }
+    
+    static public class DES
+        extends JCESecretKeyFactory
+    {
+        public DES()
+        {
+            super("DES", null);
+        }
+
+        protected SecretKey engineGenerateSecret(
+            KeySpec keySpec)
+        throws InvalidKeySpecException
+        {
+            if (keySpec instanceof DESKeySpec)
+            {
+                DESKeySpec desKeySpec = (DESKeySpec)keySpec;
+                return new SecretKeySpec(desKeySpec.getKey(), "DES");
+            }
+
+            return super.engineGenerateSecret(keySpec);
+        }
+    }
+
+    static public class DESede
+        extends JCESecretKeyFactory
+    {
+        public DESede()
+        {
+            super("DESede", null);
+        }
+
+        protected KeySpec engineGetKeySpec(
+            SecretKey key,
+            Class keySpec)
+        throws InvalidKeySpecException
+        {
+            if (keySpec == null)
+            {
+                throw new InvalidKeySpecException("keySpec parameter is null");
+            }
+            if (key == null)
+            {
+                throw new InvalidKeySpecException("key parameter is null");
+            }
+            
+            if (SecretKeySpec.class.isAssignableFrom(keySpec))
+            {
+                return new SecretKeySpec(key.getEncoded(), algName);
+            }
+            else if (DESedeKeySpec.class.isAssignableFrom(keySpec))
+            {
+                byte[]  bytes = key.getEncoded();
+
+                try
+                {
+                    if (bytes.length == 16)
+                    {
+                        byte[]  longKey = new byte[24];
+
+                        System.arraycopy(bytes, 0, longKey, 0, 16);
+                        System.arraycopy(bytes, 0, longKey, 16, 8);
+
+                        return new DESedeKeySpec(longKey);
+                    }
+                    else
+                    {
+                        return new DESedeKeySpec(bytes);
+                    }
+                }
+                catch (Exception e)
+                {
+                    throw new InvalidKeySpecException(e.toString());
+                }
+            }
+
+            throw new InvalidKeySpecException("Invalid KeySpec");
+        }
+
+        protected SecretKey engineGenerateSecret(
+            KeySpec keySpec)
+        throws InvalidKeySpecException
+        {
+            if (keySpec instanceof DESedeKeySpec)
+            {
+                DESedeKeySpec desKeySpec = (DESedeKeySpec)keySpec;
+                return new SecretKeySpec(desKeySpec.getKey(), "DESede");
+            }
+
+            return super.engineGenerateSecret(keySpec);
+        }
+    }
+    
+   /**
+    * PBEWithMD5AndDES
+    */
+   static public class PBEWithMD5AndDES
+       extends DESPBEKeyFactory
+   {
+       public PBEWithMD5AndDES()
+       {
+           super("PBEwithMD5andDES", null, true, PKCS5S1, MD5, 64, 64);
+       }
+   }
+
+   /**
+    * PBEWithMD5AndRC2
+    */
+   static public class PBEWithMD5AndRC2
+       extends PBEKeyFactory
+   {
+       public PBEWithMD5AndRC2()
+       {
+           super("PBEwithMD5andRC2", null, true, PKCS5S1, MD5, 64, 64);
+       }
+   }
+
+   /**
+    * PBEWithSHA1AndDES
+    */
+   static public class PBEWithSHA1AndDES
+       extends PBEKeyFactory
+   {
+       public PBEWithSHA1AndDES()
+       {
+           super("PBEwithSHA1andDES", null, true, PKCS5S1, SHA1, 64, 64);
+       }
+   }
+
+   /**
+    * PBEWithSHA1AndRC2
+    */
+   static public class PBEWithSHA1AndRC2
+       extends PBEKeyFactory
+   {
+       public PBEWithSHA1AndRC2()
+       {
+           super("PBEwithSHA1andRC2", null, true, PKCS5S1, SHA1, 64, 64);
+       }
+   }
+
+   /**
+    * PBEWithSHAAnd3-KeyTripleDES-CBC
+    */
+   static public class PBEWithSHAAndDES3Key
+       extends PBEKeyFactory
+   {
+       public PBEWithSHAAndDES3Key()
+       {
+           super("PBEwithSHAandDES3Key-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, true, PKCS12, SHA1, 192, 64);
+       }
+   }
+
+   /**
+    * PBEWithSHAAnd2-KeyTripleDES-CBC
+    */
+   static public class PBEWithSHAAndDES2Key
+       extends PBEKeyFactory
+   {
+       public PBEWithSHAAndDES2Key()
+       {
+           super("PBEwithSHAandDES2Key-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC, true, PKCS12, SHA1, 128, 64);
+       }
+   }
+
+   /**
+    * PBEWithSHAAnd128BitRC2-CBC
+    */
+   static public class PBEWithSHAAnd128BitRC2
+       extends PBEKeyFactory
+   {
+       public PBEWithSHAAnd128BitRC2()
+       {
+           super("PBEwithSHAand128BitRC2-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC, true, PKCS12, SHA1, 128, 64);
+       }
+   }
+
+   /**
+    * PBEWithSHAAnd40BitRC2-CBC
+    */
+   static public class PBEWithSHAAnd40BitRC2
+       extends PBEKeyFactory
+   {
+       public PBEWithSHAAnd40BitRC2()
+       {
+           super("PBEwithSHAand40BitRC2-CBC", PKCSObjectIdentifiers.pbewithSHAAnd40BitRC2_CBC, true, PKCS12, SHA1, 40, 64);
+       }
+   }
+
+   /**
+    * PBEWithSHAAndTwofish-CBC
+    */
+   static public class PBEWithSHAAndTwofish
+       extends PBEKeyFactory
+   {
+       public PBEWithSHAAndTwofish()
+       {
+           super("PBEwithSHAandTwofish-CBC", null, true, PKCS12, SHA1, 256, 128);
+       }
+   }
+
+   /**
+    * PBEWithSHAAndIDEA-CBC
+    */
+   static public class PBEWithSHAAndIDEA
+       extends PBEKeyFactory
+   {
+       public PBEWithSHAAndIDEA()
+       {
+           super("PBEwithSHAandIDEA-CBC", null, true, PKCS12, SHA1, 128, 64);
+       }
+   }
+   
+   /**
+    * PBEWithSHAAnd128BitRC4
+    */
+   static public class PBEWithSHAAnd128BitRC4
+       extends PBEKeyFactory
+   {
+       public PBEWithSHAAnd128BitRC4()
+       {
+           super("PBEWithSHAAnd128BitRC4", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, true, PKCS12, SHA1, 128, 0);
+       }
+   }
+
+   /**
+    * PBEWithSHAAnd40BitRC4
+    */
+   static public class PBEWithSHAAnd40BitRC4
+       extends PBEKeyFactory
+   {
+       public PBEWithSHAAnd40BitRC4()
+       {
+           super("PBEWithSHAAnd128BitRC4", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, true, PKCS12, SHA1, 40, 0);
+       }
+   }
+   
+   /**
+    * PBEWithHmacRIPEMD160
+    */
+   public static class PBEWithRIPEMD160
+       extends PBEKeyFactory
+   {
+       public PBEWithRIPEMD160()
+       {
+           super("PBEwithHmacRIPEMD160", null, false, PKCS12, RIPEMD160, 160, 0);
+       }
+   }
+
+   /**
+    * PBEWithHmacSHA
+    */
+   public static class PBEWithSHA
+       extends PBEKeyFactory
+   {
+       public PBEWithSHA()
+       {
+           super("PBEwithHmacSHA", null, false, PKCS12, SHA1, 160, 0);
+       }
+   }
+
+   /**
+    * PBEWithHmacTiger
+    */
+   public static class PBEWithTiger
+       extends PBEKeyFactory
+   {
+       public PBEWithTiger()
+       {
+           super("PBEwithHmacTiger", null, false, PKCS12, TIGER, 192, 0);
+       }
+   }
+   
+   /**
+    * PBEWithSHA1And128BitAES-BC
+    */
+   static public class PBEWithSHAAnd128BitAESBC
+       extends PBEKeyFactory
+   {
+       public PBEWithSHAAnd128BitAESBC()
+       {
+           super("PBEWithSHA1And128BitAES-CBC-BC", null, true, PKCS12, SHA1, 128, 128);
+       }
+   }
+   
+   /**
+    * PBEWithSHA1And192BitAES-BC
+    */
+   static public class PBEWithSHAAnd192BitAESBC
+       extends PBEKeyFactory
+   {
+       public PBEWithSHAAnd192BitAESBC()
+       {
+           super("PBEWithSHA1And192BitAES-CBC-BC", null, true, PKCS12, SHA1, 192, 128);
+       }
+   }
+   
+   /**
+    * PBEWithSHA1And256BitAES-BC
+    */
+   static public class PBEWithSHAAnd256BitAESBC
+       extends PBEKeyFactory
+   {
+       public PBEWithSHAAnd256BitAESBC()
+       {
+           super("PBEWithSHA1And256BitAES-CBC-BC", null, true, PKCS12, SHA1, 256, 128);
+       }
+   }
+   
+   /**
+    * PBEWithSHA256And128BitAES-BC
+    */
+   static public class PBEWithSHA256And128BitAESBC
+       extends PBEKeyFactory
+   {
+       public PBEWithSHA256And128BitAESBC()
+       {
+           super("PBEWithSHA256And128BitAES-CBC-BC", null, true, PKCS12, SHA256, 128, 128);
+       }
+   }
+   
+   /**
+    * PBEWithSHA256And192BitAES-BC
+    */
+   static public class PBEWithSHA256And192BitAESBC
+       extends PBEKeyFactory
+   {
+       public PBEWithSHA256And192BitAESBC()
+       {
+           super("PBEWithSHA256And192BitAES-CBC-BC", null, true, PKCS12, SHA256, 192, 128);
+       }
+   }
+   
+   /**
+    * PBEWithSHA256And256BitAES-BC
+    */
+   static public class PBEWithSHA256And256BitAESBC
+       extends PBEKeyFactory
+   {
+       public PBEWithSHA256And256BitAESBC()
+       {
+           super("PBEWithSHA256And256BitAES-CBC-BC", null, true, PKCS12, SHA256, 256, 128);
+       }
+   }
+   
+   /**
+    * PBEWithMD5And128BitAES-OpenSSL
+    */
+   static public class PBEWithMD5And128BitAESCBCOpenSSL
+       extends PBEKeyFactory
+   {
+       public PBEWithMD5And128BitAESCBCOpenSSL()
+       {
+           super("PBEWithMD5And128BitAES-CBC-OpenSSL", null, true, OPENSSL, MD5, 128, 128);
+       }
+   }
+   
+   /**
+    * PBEWithMD5And192BitAES-OpenSSL
+    */
+   static public class PBEWithMD5And192BitAESCBCOpenSSL
+       extends PBEKeyFactory
+   {
+       public PBEWithMD5And192BitAESCBCOpenSSL()
+       {
+           super("PBEWithMD5And192BitAES-CBC-OpenSSL", null, true, OPENSSL, MD5, 192, 128);
+       }
+   }
+   
+   /**
+    * PBEWithMD5And256BitAES-OpenSSL
+    */
+   static public class PBEWithMD5And256BitAESCBCOpenSSL
+       extends PBEKeyFactory
+   {
+       public PBEWithMD5And256BitAESCBCOpenSSL()
+       {
+           super("PBEWithMD5And256BitAES-CBC-OpenSSL", null, true, OPENSSL, MD5, 256, 128);
+       }
+   }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEStreamCipher.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEStreamCipher.java
new file mode 100644
index 0000000..fe1a2be
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JCEStreamCipher.java
@@ -0,0 +1,559 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+import javax.crypto.spec.RC5ParameterSpec;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.StreamBlockCipher;
+import org.bouncycastle.crypto.StreamCipher;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.engines.BlowfishEngine;
+// END android-removed
+import org.bouncycastle.crypto.engines.DESEngine;
+import org.bouncycastle.crypto.engines.DESedeEngine;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.engines.IDEAEngine;
+// import org.bouncycastle.crypto.engines.RC4Engine;
+// import org.bouncycastle.crypto.engines.SkipjackEngine;
+// import org.bouncycastle.crypto.engines.TwofishEngine;
+// END android-removed
+import org.bouncycastle.crypto.modes.CFBBlockCipher;
+import org.bouncycastle.crypto.modes.OFBBlockCipher;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+public class JCEStreamCipher
+    extends WrapCipherSpi implements PBE
+{
+    //
+    // specs we can handle.
+    //
+    private Class[]                 availableSpecs =
+                                    {
+                                        RC2ParameterSpec.class,
+                                        RC5ParameterSpec.class,
+                                        IvParameterSpec.class,
+                                        PBEParameterSpec.class
+                                    };
+
+    private StreamCipher       cipher;
+    private ParametersWithIV   ivParam;
+
+    private int                     ivLength = 0;
+
+    private PBEParameterSpec        pbeSpec = null;
+    private String                  pbeAlgorithm = null;
+
+    protected JCEStreamCipher(
+        StreamCipher engine)
+    {
+        cipher = engine;
+    }
+        
+    protected JCEStreamCipher(
+        BlockCipher engine,
+        int         ivLength)
+    {
+        this.ivLength = ivLength;
+
+        cipher = new StreamBlockCipher(engine);
+    }
+
+    protected int engineGetBlockSize() 
+    {
+        return 0;
+    }
+
+    protected byte[] engineGetIV() 
+    {
+        return (ivParam != null) ? ivParam.getIV() : null;
+    }
+
+    protected int engineGetKeySize(
+        Key     key) 
+    {
+        return key.getEncoded().length * 8;
+    }
+
+    protected int engineGetOutputSize(
+        int     inputLen) 
+    {
+        return inputLen;
+    }
+
+    protected AlgorithmParameters engineGetParameters() 
+    {
+        if (engineParams == null)
+        {
+            if (pbeSpec != null)
+            {
+                try
+                {
+                    AlgorithmParameters engineParams = AlgorithmParameters.getInstance(pbeAlgorithm, "BC");
+                    engineParams.init(pbeSpec);
+                    
+                    return engineParams;
+                }
+                catch (Exception e)
+                {
+                    return null;
+                }
+            }
+        }
+        
+        return engineParams;
+    }
+
+    /**
+     * should never be called.
+     */
+    protected void engineSetMode(
+        String  mode) 
+    {
+        if (!mode.equalsIgnoreCase("ECB"))
+        {
+            throw new IllegalArgumentException("can't support mode " + mode);
+        }
+    }
+
+    /**
+     * should never be called.
+     */
+    protected void engineSetPadding(
+        String  padding) 
+    throws NoSuchPaddingException
+    {
+        if (!padding.equalsIgnoreCase("NoPadding"))
+        {
+            throw new NoSuchPaddingException("Padding " + padding + " unknown.");
+        }
+    }
+
+    protected void engineInit(
+        int                     opmode,
+        Key                     key,
+        AlgorithmParameterSpec  params,
+        SecureRandom            random) 
+        throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        CipherParameters        param;
+
+        this.pbeSpec = null;
+        this.pbeAlgorithm = null;
+        
+        this.engineParams = null;
+        
+        //
+        // basic key check
+        //
+        if (!(key instanceof SecretKey))
+        {
+            throw new InvalidKeyException("Key for algorithm " + key.getAlgorithm() + " not suitable for symmetric enryption.");
+        }
+        
+        if (key instanceof JCEPBEKey)
+        {
+            JCEPBEKey   k = (JCEPBEKey)key;
+            
+            if (k.getOID() != null)
+            {
+                pbeAlgorithm = k.getOID().getId();
+            }
+            else
+            {
+                pbeAlgorithm = k.getAlgorithm();
+            }
+            
+            if (k.getParam() != null)
+            {
+                param = k.getParam();                
+                pbeSpec = new PBEParameterSpec(k.getSalt(), k.getIterationCount());
+            }
+            else if (params instanceof PBEParameterSpec)
+            {
+                param = PBE.Util.makePBEParameters(k, params, cipher.getAlgorithmName());
+                pbeSpec = (PBEParameterSpec)params;
+            }
+            else
+            {
+                throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
+            }
+            
+            if (k.getIvSize() != 0)
+            {
+                ivParam = (ParametersWithIV)param;
+            }
+        }
+        else if (params == null)
+        {
+            param = new KeyParameter(key.getEncoded());
+        }
+        else if (params instanceof IvParameterSpec)
+        {
+            param = new ParametersWithIV(new KeyParameter(key.getEncoded()), ((IvParameterSpec)params).getIV());
+            ivParam = (ParametersWithIV)param;
+        }
+        else
+        {
+            throw new IllegalArgumentException("unknown parameter type.");
+        }
+
+        if ((ivLength != 0) && !(param instanceof ParametersWithIV))
+        {
+            SecureRandom    ivRandom = random;
+
+            if (ivRandom == null)
+            {
+                ivRandom = new SecureRandom();
+            }
+
+            if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE))
+            {
+                byte[]  iv = new byte[ivLength];
+
+                ivRandom.nextBytes(iv);
+                param = new ParametersWithIV(param, iv);
+                ivParam = (ParametersWithIV)param;
+            }
+            else
+            {
+                throw new InvalidAlgorithmParameterException("no IV set when one expected");
+            }
+        }
+
+        switch (opmode)
+        {
+        case Cipher.ENCRYPT_MODE:
+        case Cipher.WRAP_MODE:
+            cipher.init(true, param);
+            break;
+        case Cipher.DECRYPT_MODE:
+        case Cipher.UNWRAP_MODE:
+            cipher.init(false, param);
+            break;
+        default:
+            System.out.println("eeek!");
+        }
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key                 key,
+        AlgorithmParameters params,
+        SecureRandom        random) 
+        throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        AlgorithmParameterSpec  paramSpec = null;
+
+        if (params != null)
+        {
+            for (int i = 0; i != availableSpecs.length; i++)
+            {
+                try
+                {
+                    paramSpec = params.getParameterSpec(availableSpecs[i]);
+                    break;
+                }
+                catch (Exception e)
+                {
+                    continue;
+                }
+            }
+
+            if (paramSpec == null)
+            {
+                throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString());
+            }
+        }
+
+        engineInit(opmode, key, paramSpec, random);
+        engineParams = params;
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key                 key,
+        SecureRandom        random) 
+        throws InvalidKeyException
+    {
+        try
+        {
+            engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+        }
+        catch (InvalidAlgorithmParameterException e)
+        {
+            throw new InvalidKeyException(e.getMessage());
+        }
+    }
+
+    protected byte[] engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen) 
+    {
+        byte[]  out = new byte[inputLen];
+
+        cipher.processBytes(input, inputOffset, inputLen, out, 0);
+
+        return out;
+    }
+
+    protected int engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset) 
+        throws ShortBufferException 
+    {
+        try
+        {
+        cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+
+        return inputLen;
+        }
+        catch (DataLengthException e)
+        {
+            throw new ShortBufferException(e.getMessage());
+        }
+    }
+
+    protected byte[] engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen) 
+    {
+        if (inputLen != 0)
+        {
+            byte[] out = engineUpdate(input, inputOffset, inputLen);
+
+            cipher.reset();
+            
+            return out;
+        }
+
+        cipher.reset();
+        
+        return new byte[0];
+    }
+
+    protected int engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset) 
+    {
+        if (inputLen != 0)
+        {
+            cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+        }
+
+        cipher.reset();
+        
+        return inputLen;
+    }
+
+    /*
+     * The ciphers that inherit from us.
+     */
+
+    /**
+     * DES
+     */
+    static public class DES_CFB8
+        extends JCEStreamCipher
+    {
+        public DES_CFB8()
+        {
+            super(new CFBBlockCipher(new DESEngine(), 8), 64);
+        }
+    }
+
+    /**
+     * DESede
+     */
+    static public class DESede_CFB8
+        extends JCEStreamCipher
+    {
+        public DESede_CFB8()
+        {
+            super(new CFBBlockCipher(new DESedeEngine(), 8), 64);
+        }
+    }
+
+// BEGIN android-removed
+//    /**
+//     * SKIPJACK
+//     */
+//    static public class Skipjack_CFB8
+//        extends JCEStreamCipher
+//    {
+//        public Skipjack_CFB8()
+//        {
+//            super(new CFBBlockCipher(new SkipjackEngine(), 8), 64);
+//        }
+//    }
+//
+//    /**
+//     * Blowfish
+//     */
+//    static public class Blowfish_CFB8
+//        extends JCEStreamCipher
+//    {
+//        public Blowfish_CFB8()
+//        {
+//            super(new CFBBlockCipher(new BlowfishEngine(), 8), 64);
+//        }
+//    }
+//
+//    /**
+//     * Twofish
+//     */
+//    static public class Twofish_CFB8
+//        extends JCEStreamCipher
+//    {
+//        public Twofish_CFB8()
+//        {
+//            super(new CFBBlockCipher(new TwofishEngine(), 8), 128);
+//        }
+//    }
+//
+//    /**
+//     * IDEA
+//     */
+//    static public class IDEA_CFB8
+//        extends JCEStreamCipher
+//    {
+//        public IDEA_CFB8()
+//        {
+//            super(new CFBBlockCipher(new IDEAEngine(), 8), 64);
+//        }
+//    }
+// END android-removed
+
+    /**
+     * DES
+     */
+    static public class DES_OFB8
+        extends JCEStreamCipher
+    {
+        public DES_OFB8()
+        {
+            super(new OFBBlockCipher(new DESEngine(), 8), 64);
+        }
+    }
+
+    /**
+     * DESede
+     */
+    static public class DESede_OFB8
+        extends JCEStreamCipher
+    {
+        public DESede_OFB8()
+        {
+            super(new OFBBlockCipher(new DESedeEngine(), 8), 64);
+        }
+    }
+
+//  BEGIN android-removed
+//    /**
+//     * SKIPJACK
+//     */
+//    static public class Skipjack_OFB8
+//        extends JCEStreamCipher
+//    {
+//        public Skipjack_OFB8()
+//        {
+//            super(new OFBBlockCipher(new SkipjackEngine(), 8), 64);
+//        }
+//    }
+//
+//    /**
+//     * Blowfish
+//     */
+//    static public class Blowfish_OFB8
+//        extends JCEStreamCipher
+//    {
+//        public Blowfish_OFB8()
+//        {
+//            super(new OFBBlockCipher(new BlowfishEngine(), 8), 64);
+//        }
+//    }
+//
+//    /**
+//     * Twofish
+//     */
+//    static public class Twofish_OFB8
+//        extends JCEStreamCipher
+//    {
+//        public Twofish_OFB8()
+//        {
+//            super(new OFBBlockCipher(new TwofishEngine(), 8), 128);
+//        }
+//    }
+//
+//    /**
+//     * IDEA
+//     */
+//    static public class IDEA_OFB8
+//        extends JCEStreamCipher
+//    {
+//        public IDEA_OFB8()
+//        {
+//            super(new OFBBlockCipher(new IDEAEngine(), 8), 64);
+//        }
+//    }
+//
+//    /**
+//     * RC4
+//     */
+//    static public class RC4
+//        extends JCEStreamCipher
+//    {
+//        public RC4()
+//        {
+//            super(new RC4Engine());
+//        }
+//    }
+//
+//    /**
+//     * PBEWithSHAAnd128BitRC4
+//     */
+//    static public class PBEWithSHAAnd128BitRC4
+//        extends JCEStreamCipher
+//    {
+//        public PBEWithSHAAnd128BitRC4()
+//        {
+//            super(new RC4Engine());
+//        }
+//    }
+//
+//    /**
+//     * PBEWithSHAAnd40BitRC4
+//     */
+//    static public class PBEWithSHAAnd40BitRC4
+//        extends JCEStreamCipher
+//    {
+//        public PBEWithSHAAnd40BitRC4()
+//        {
+//            super(new RC4Engine());
+//        }
+//    }
+// END android-removed
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java
new file mode 100644
index 0000000..a72cb13
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKAlgorithmParameterGenerator.java
@@ -0,0 +1,446 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.AlgorithmParameterGeneratorSpi;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+
+import javax.crypto.spec.DHGenParameterSpec;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+
+import org.bouncycastle.crypto.generators.DHParametersGenerator;
+import org.bouncycastle.crypto.generators.DSAParametersGenerator;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.generators.ElGamalParametersGenerator;
+// import org.bouncycastle.crypto.generators.GOST3410ParametersGenerator;
+// END android-removed
+import org.bouncycastle.crypto.params.DHParameters;
+import org.bouncycastle.crypto.params.DSAParameters;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.params.ElGamalParameters;
+// import org.bouncycastle.crypto.params.GOST3410Parameters;
+// import org.bouncycastle.jce.spec.GOST3410ParameterSpec;
+// import org.bouncycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
+// END android-removed
+
+public abstract class JDKAlgorithmParameterGenerator
+    extends AlgorithmParameterGeneratorSpi
+{
+    protected SecureRandom  random;
+    protected int           strength = 1024;
+
+    protected void engineInit(
+        int             strength,
+        SecureRandom    random)
+    {
+        this.strength = strength;
+        this.random = random;
+    }
+
+    public static class DH
+        extends JDKAlgorithmParameterGenerator
+    {
+        private int l = 0;
+
+        protected void engineInit(
+            AlgorithmParameterSpec  genParamSpec,
+            SecureRandom            random)
+            throws InvalidAlgorithmParameterException
+        {
+            if (!(genParamSpec instanceof DHGenParameterSpec))
+            {
+                throw new InvalidAlgorithmParameterException("DH parameter generator requires a DHGenParameterSpec for initialisation");
+            }
+            DHGenParameterSpec  spec = (DHGenParameterSpec)genParamSpec;
+
+            this.strength = spec.getPrimeSize();
+            this.l = spec.getExponentSize();
+            this.random = random;
+        }
+
+        protected AlgorithmParameters engineGenerateParameters()
+        {
+            DHParametersGenerator        pGen = new DHParametersGenerator();
+
+            if (random != null)
+            {
+                pGen.init(strength, 20, random);
+            }
+            else
+            {
+                pGen.init(strength, 20, new SecureRandom());
+            }
+
+            DHParameters                p = pGen.generateParameters();
+
+            AlgorithmParameters params;
+
+            try
+            {
+                params = AlgorithmParameters.getInstance("DH", "BC");
+                params.init(new DHParameterSpec(p.getP(), p.getG(), l));
+            }
+            catch (Exception e)
+            {
+                throw new RuntimeException(e.getMessage());
+            }
+
+            return params;
+        }
+    }
+
+    public static class DSA
+        extends JDKAlgorithmParameterGenerator
+    {
+        protected void engineInit(
+            AlgorithmParameterSpec  genParamSpec,
+            SecureRandom            random)
+            throws InvalidAlgorithmParameterException
+        {
+            throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for DSA parameter generation.");
+        }
+
+        protected AlgorithmParameters engineGenerateParameters()
+        {
+            DSAParametersGenerator pGen = new DSAParametersGenerator();
+
+            if (random != null)
+            {
+                pGen.init(strength, 20, random);
+            }
+            else
+            {
+                pGen.init(strength, 20, new SecureRandom());
+            }
+
+            DSAParameters p = pGen.generateParameters();
+
+            AlgorithmParameters params;
+
+            try
+            {
+                params = AlgorithmParameters.getInstance("DSA", "BC");
+                params.init(new DSAParameterSpec(p.getP(), p.getQ(), p.getG()));
+            }
+            catch (Exception e)
+            {
+                throw new RuntimeException(e.getMessage());
+            }
+
+            return params;
+        }
+    }
+
+// BEGIN android-removed
+//    public static class GOST3410
+//        extends JDKAlgorithmParameterGenerator
+//    {
+//        protected void engineInit(
+//                AlgorithmParameterSpec  genParamSpec,
+//                SecureRandom            random)
+//        throws InvalidAlgorithmParameterException
+//        {
+//            throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for GOST3410 parameter generation.");
+//        }
+//        
+//        protected AlgorithmParameters engineGenerateParameters()
+//        {
+//            GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator();
+//            
+//            if (random != null)
+//            {
+//                pGen.init(strength, 2, random);
+//            }
+//            else
+//            {
+//                pGen.init(strength, 2, new SecureRandom());
+//            }
+//            
+//            GOST3410Parameters p = pGen.generateParameters();
+//            
+//            AlgorithmParameters params;
+//            
+//            try
+//            {
+//                params = AlgorithmParameters.getInstance("GOST3410", "BC");
+//                params.init(new GOST3410ParameterSpec(new GOST3410PublicKeyParameterSetSpec(p.getP(), p.getQ(), p.getA())));
+//            }
+//            catch (Exception e)
+//            {
+//                throw new RuntimeException(e.getMessage());
+//            }
+//            
+//            return params;
+//        }
+//    }
+//    
+//    public static class ElGamal
+//        extends JDKAlgorithmParameterGenerator
+//    {
+//        private int l = 0;
+//        
+//        protected void engineInit(
+//            AlgorithmParameterSpec  genParamSpec,
+//            SecureRandom            random)
+//            throws InvalidAlgorithmParameterException
+//        {
+//            if (!(genParamSpec instanceof DHGenParameterSpec))
+//            {
+//                throw new InvalidAlgorithmParameterException("DH parameter generator requires a DHGenParameterSpec for initialisation");
+//            }
+//            DHGenParameterSpec  spec = (DHGenParameterSpec)genParamSpec;
+//
+//            this.strength = spec.getPrimeSize();
+//            this.l = spec.getExponentSize();
+//            this.random = random;
+//        }
+//
+//        protected AlgorithmParameters engineGenerateParameters()
+//        {
+//            ElGamalParametersGenerator pGen = new ElGamalParametersGenerator();
+//
+//            if (random != null)
+//            {
+//                pGen.init(strength, 20, random);
+//            }
+//            else
+//            {
+//                pGen.init(strength, 20, new SecureRandom());
+//            }
+//
+//            ElGamalParameters p = pGen.generateParameters();
+//
+//            AlgorithmParameters params;
+//
+//            try
+//            {
+//                params = AlgorithmParameters.getInstance("ElGamal", "BC");
+//                params.init(new DHParameterSpec(p.getP(), p.getG(), l));
+//            }
+//            catch (Exception e)
+//            {
+//                throw new RuntimeException(e.getMessage());
+//            }
+//
+//            return params;
+//        }
+//    }
+// END android-removed
+
+    public static class DES
+        extends JDKAlgorithmParameterGenerator
+    {
+        protected void engineInit(
+            AlgorithmParameterSpec  genParamSpec,
+            SecureRandom            random)
+            throws InvalidAlgorithmParameterException
+        {
+            throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for DES parameter generation.");
+        }
+
+        protected AlgorithmParameters engineGenerateParameters()
+        {
+            byte[]  iv = new byte[8];
+
+            if (random == null)
+            {
+                random = new SecureRandom();
+            }
+
+            random.nextBytes(iv);
+
+            AlgorithmParameters params;
+
+            try
+            {
+                params = AlgorithmParameters.getInstance("DES", "BC");
+                params.init(new IvParameterSpec(iv));
+            }
+            catch (Exception e)
+            {
+                throw new RuntimeException(e.getMessage());
+            }
+
+            return params;
+        }
+    }
+
+    public static class RC2
+        extends JDKAlgorithmParameterGenerator
+    {
+        RC2ParameterSpec    spec = null;
+
+        protected void engineInit(
+            AlgorithmParameterSpec  genParamSpec,
+            SecureRandom            random)
+            throws InvalidAlgorithmParameterException
+        {
+            if (genParamSpec instanceof RC2ParameterSpec)
+            {
+                spec = (RC2ParameterSpec)genParamSpec;
+                return;
+            }
+
+            throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for RC2 parameter generation.");
+        }
+
+        protected AlgorithmParameters engineGenerateParameters()
+        {
+            AlgorithmParameters params;
+
+            if (spec == null)
+            {
+                byte[]  iv = new byte[8];
+
+                if (random == null)
+                {
+                    random = new SecureRandom();
+                }
+
+                random.nextBytes(iv);
+
+                try
+                {
+                    params = AlgorithmParameters.getInstance("RC2", "BC");
+                    params.init(new IvParameterSpec(iv));
+                }
+                catch (Exception e)
+                {
+                    throw new RuntimeException(e.getMessage());
+                }
+            }
+            else
+            {
+                try
+                {
+                    params = AlgorithmParameters.getInstance("RC2", "BC");
+                    params.init(spec);
+                }
+                catch (Exception e)
+                {
+                    throw new RuntimeException(e.getMessage());
+                }
+            }
+
+            return params;
+        }
+    }
+
+    public static class AES
+        extends JDKAlgorithmParameterGenerator
+    {
+        protected void engineInit(
+            AlgorithmParameterSpec  genParamSpec,
+            SecureRandom            random)
+            throws InvalidAlgorithmParameterException
+        {
+            throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for AES parameter generation.");
+        }
+
+        protected AlgorithmParameters engineGenerateParameters()
+        {
+            byte[]  iv = new byte[16];
+
+            if (random == null)
+            {
+                random = new SecureRandom();
+            }
+
+            random.nextBytes(iv);
+
+            AlgorithmParameters params;
+
+            try
+            {
+                params = AlgorithmParameters.getInstance("AES", "BC");
+                params.init(new IvParameterSpec(iv));
+            }
+            catch (Exception e)
+            {
+                throw new RuntimeException(e.getMessage());
+            }
+
+            return params;
+        }
+    }
+
+    public static class IDEA
+        extends JDKAlgorithmParameterGenerator
+    {
+        protected void engineInit(
+            AlgorithmParameterSpec  genParamSpec,
+            SecureRandom            random)
+            throws InvalidAlgorithmParameterException
+        {
+            throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for IDEA parameter generation.");
+        }
+
+        protected AlgorithmParameters engineGenerateParameters()
+        {
+            byte[]  iv = new byte[8];
+
+            if (random == null)
+            {
+                random = new SecureRandom();
+            }
+
+            random.nextBytes(iv);
+
+            AlgorithmParameters params;
+
+            try
+            {
+                params = AlgorithmParameters.getInstance("IDEA", "BC");
+                params.init(new IvParameterSpec(iv));
+            }
+            catch (Exception e)
+            {
+                throw new RuntimeException(e.getMessage());
+            }
+
+            return params;
+        }
+    }
+
+    public static class CAST5
+        extends JDKAlgorithmParameterGenerator
+    {
+        protected void engineInit(
+            AlgorithmParameterSpec  genParamSpec,
+            SecureRandom            random)
+            throws InvalidAlgorithmParameterException
+        {
+            throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for CAST5 parameter generation.");
+        }
+
+        protected AlgorithmParameters engineGenerateParameters()
+        {
+            byte[]  iv = new byte[8];
+
+            if (random == null)
+            {
+                random = new SecureRandom();
+            }
+
+            random.nextBytes(iv);
+
+            AlgorithmParameters params;
+
+            try
+            {
+                params = AlgorithmParameters.getInstance("CAST5", "BC");
+                params.init(new IvParameterSpec(iv));
+            }
+            catch (Exception e)
+            {
+                throw new RuntimeException(e.getMessage());
+            }
+
+            return params;
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java
new file mode 100644
index 0000000..a7f8647
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java
@@ -0,0 +1,1461 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.AlgorithmParametersSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.MGF1ParameterSpec;
+import java.security.spec.PSSParameterSpec;
+
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.PSource;
+import javax.crypto.spec.RC2ParameterSpec;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.asn1.DERSequence;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
+// import org.bouncycastle.asn1.misc.CAST5CBCParameters;
+// END android-removed
+import org.bouncycastle.asn1.misc.IDEACBCPar;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.oiw.ElGamalParameter;
+// END android-removed
+import org.bouncycastle.asn1.pkcs.DHParameter;
+import org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.RC2CBCParameter;
+import org.bouncycastle.asn1.pkcs.RSAESOAEPparams;
+import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.DSAParameter;
+// BEGIN android-removed
+// import org.bouncycastle.jce.spec.ElGamalParameterSpec;
+// import org.bouncycastle.jce.spec.GOST3410ParameterSpec;
+// import org.bouncycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
+// END android-removed
+import org.bouncycastle.jce.spec.IESParameterSpec;
+
+public abstract class JDKAlgorithmParameters
+    extends AlgorithmParametersSpi
+{
+    public static class IVAlgorithmParameters
+        extends JDKAlgorithmParameters
+    {
+        private byte[]  iv;
+
+        protected byte[] engineGetEncoded() 
+            throws IOException
+        {
+            return engineGetEncoded("ASN.1");
+        }
+
+        protected byte[] engineGetEncoded(
+            String format) 
+            throws IOException
+        {
+            if (format == null)
+            {
+                return engineGetEncoded("ASN.1");
+            }
+            
+            if (format.equals("RAW"))
+            {
+                byte[]  tmp = new byte[iv.length];
+
+                System.arraycopy(iv, 0, tmp, 0, iv.length);
+                return tmp;
+            }
+            else if (format.equals("ASN.1"))
+            {
+                return new DEROctetString(engineGetEncoded("RAW")).getEncoded();
+            }
+
+            return null;
+        }
+
+        protected AlgorithmParameterSpec engineGetParameterSpec(
+            Class paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec == IvParameterSpec.class)
+            {
+                return new IvParameterSpec(iv);
+            }
+
+            throw new InvalidParameterSpecException("unknown parameter spec passed to IV parameters object.");
+        }
+
+        protected void engineInit(
+            AlgorithmParameterSpec paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (!(paramSpec instanceof IvParameterSpec))
+            {
+                throw new InvalidParameterSpecException("IvParameterSpec required to initialise a IV parameters algorithm parameters object");
+            }
+
+            this.iv = ((IvParameterSpec)paramSpec).getIV();
+        }
+
+        protected void engineInit(
+            byte[] params) 
+            throws IOException
+        {
+            //
+            // check that we don't have a DER encoded octet string
+            //
+            if ((params.length % 8) != 0
+                    && params[0] == 0x04 && params[1] == params.length - 2)
+            {
+                ASN1InputStream         aIn = new ASN1InputStream(params);
+                ASN1OctetString         oct = (ASN1OctetString)aIn.readObject();
+
+                params = oct.getOctets();
+            }
+
+            this.iv = new byte[params.length];
+
+            System.arraycopy(params, 0, iv, 0, iv.length);
+        }
+
+        protected void engineInit(
+            byte[] params,
+            String format) 
+            throws IOException
+        {
+            if (format.equals("RAW"))
+            {
+                engineInit(params);
+                return;
+            }
+            else if (format.equals("ASN.1"))
+            {
+                ASN1InputStream         aIn = new ASN1InputStream(params);
+                
+                try
+                {
+                    ASN1OctetString         oct = (ASN1OctetString)aIn.readObject();
+    
+                    engineInit(oct.getOctets());
+                }
+                catch (Exception e)
+                {
+                    throw new IOException("Exception decoding: " + e);
+                }
+                
+                return;
+            }
+
+            throw new IOException("Unknown parameters format in IV parameters object");
+        }
+
+        protected String engineToString() 
+        {
+            return "IV Parameters";
+        }
+    }
+
+    public static class IDEAAlgorithmParameters
+        extends JDKAlgorithmParameters
+    {
+        private byte[]  iv;
+
+        protected byte[] engineGetEncoded() 
+            throws IOException
+        {
+            return engineGetEncoded("ASN.1");
+        }
+
+        protected byte[] engineGetEncoded(
+            String format) 
+            throws IOException
+        {
+            if (format == null)
+            {
+                return engineGetEncoded("ASN.1");
+            }
+            
+            if (format.equals("RAW"))
+            {
+                byte[]  tmp = new byte[iv.length];
+
+                System.arraycopy(iv, 0, tmp, 0, iv.length);
+                return tmp;
+            }
+            else if (format.equals("ASN.1"))
+            {
+                return new IDEACBCPar(engineGetEncoded("RAW")).getEncoded();
+            }
+
+            return null;
+        }
+
+        protected AlgorithmParameterSpec engineGetParameterSpec(
+            Class paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec == IvParameterSpec.class)
+            {
+                return new IvParameterSpec(iv);
+            }
+
+            throw new InvalidParameterSpecException("unknown parameter spec passed to IV parameters object.");
+        }
+
+        protected void engineInit(
+            AlgorithmParameterSpec paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (!(paramSpec instanceof IvParameterSpec))
+            {
+                throw new InvalidParameterSpecException("IvParameterSpec required to initialise a IV parameters algorithm parameters object");
+            }
+
+            this.iv = ((IvParameterSpec)paramSpec).getIV();
+        }
+
+        protected void engineInit(
+            byte[] params) 
+            throws IOException
+        {
+            this.iv = new byte[params.length];
+
+            System.arraycopy(params, 0, iv, 0, iv.length);
+        }
+
+        protected void engineInit(
+            byte[] params,
+            String format) 
+            throws IOException
+        {
+            if (format.equals("RAW"))
+            {
+                engineInit(params);
+                return;
+            }
+            else if (format.equals("ASN.1"))
+            {
+                ASN1InputStream         aIn = new ASN1InputStream(params);
+                IDEACBCPar              oct = new IDEACBCPar((ASN1Sequence)aIn.readObject());
+
+                engineInit(oct.getIV());
+                return;
+            }
+
+            throw new IOException("Unknown parameters format in IV parameters object");
+        }
+
+        protected String engineToString() 
+        {
+            return "IDEA Parameters";
+        }
+    }
+
+    public static class RC2AlgorithmParameters
+        extends JDKAlgorithmParameters
+    {
+        private short[] table = {
+           0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0,
+           0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a,
+           0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36,
+           0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c,
+           0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60,
+           0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa,
+           0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e,
+           0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf,
+           0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6,
+           0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3,
+           0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c,
+           0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2,
+           0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5,
+           0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5,
+           0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f,
+           0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab
+        };
+
+        private short[] ekb = {
+           0x5d, 0xbe, 0x9b, 0x8b, 0x11, 0x99, 0x6e, 0x4d, 0x59, 0xf3, 0x85, 0xa6, 0x3f, 0xb7, 0x83, 0xc5,
+           0xe4, 0x73, 0x6b, 0x3a, 0x68, 0x5a, 0xc0, 0x47, 0xa0, 0x64, 0x34, 0x0c, 0xf1, 0xd0, 0x52, 0xa5,
+           0xb9, 0x1e, 0x96, 0x43, 0x41, 0xd8, 0xd4, 0x2c, 0xdb, 0xf8, 0x07, 0x77, 0x2a, 0xca, 0xeb, 0xef,
+           0x10, 0x1c, 0x16, 0x0d, 0x38, 0x72, 0x2f, 0x89, 0xc1, 0xf9, 0x80, 0xc4, 0x6d, 0xae, 0x30, 0x3d,
+           0xce, 0x20, 0x63, 0xfe, 0xe6, 0x1a, 0xc7, 0xb8, 0x50, 0xe8, 0x24, 0x17, 0xfc, 0x25, 0x6f, 0xbb,
+           0x6a, 0xa3, 0x44, 0x53, 0xd9, 0xa2, 0x01, 0xab, 0xbc, 0xb6, 0x1f, 0x98, 0xee, 0x9a, 0xa7, 0x2d,
+           0x4f, 0x9e, 0x8e, 0xac, 0xe0, 0xc6, 0x49, 0x46, 0x29, 0xf4, 0x94, 0x8a, 0xaf, 0xe1, 0x5b, 0xc3,
+           0xb3, 0x7b, 0x57, 0xd1, 0x7c, 0x9c, 0xed, 0x87, 0x40, 0x8c, 0xe2, 0xcb, 0x93, 0x14, 0xc9, 0x61,
+           0x2e, 0xe5, 0xcc, 0xf6, 0x5e, 0xa8, 0x5c, 0xd6, 0x75, 0x8d, 0x62, 0x95, 0x58, 0x69, 0x76, 0xa1,
+           0x4a, 0xb5, 0x55, 0x09, 0x78, 0x33, 0x82, 0xd7, 0xdd, 0x79, 0xf5, 0x1b, 0x0b, 0xde, 0x26, 0x21,
+           0x28, 0x74, 0x04, 0x97, 0x56, 0xdf, 0x3c, 0xf0, 0x37, 0x39, 0xdc, 0xff, 0x06, 0xa4, 0xea, 0x42,
+           0x08, 0xda, 0xb4, 0x71, 0xb0, 0xcf, 0x12, 0x7a, 0x4e, 0xfa, 0x6c, 0x1d, 0x84, 0x00, 0xc8, 0x7f,
+           0x91, 0x45, 0xaa, 0x2b, 0xc2, 0xb1, 0x8f, 0xd5, 0xba, 0xf2, 0xad, 0x19, 0xb2, 0x67, 0x36, 0xf7,
+           0x0f, 0x0a, 0x92, 0x7d, 0xe3, 0x9d, 0xe9, 0x90, 0x3e, 0x23, 0x27, 0x66, 0x13, 0xec, 0x81, 0x15,
+           0xbd, 0x22, 0xbf, 0x9f, 0x7e, 0xa9, 0x51, 0x4b, 0x4c, 0xfb, 0x02, 0xd3, 0x70, 0x86, 0x31, 0xe7,
+           0x3b, 0x05, 0x03, 0x54, 0x60, 0x48, 0x65, 0x18, 0xd2, 0xcd, 0x5f, 0x32, 0x88, 0x0e, 0x35, 0xfd
+        };
+
+        private byte[]  iv;
+        private int     parameterVersion = 58;
+
+        protected byte[] engineGetEncoded() 
+        {
+            byte[]  tmp = new byte[iv.length];
+
+            System.arraycopy(iv, 0, tmp, 0, iv.length);
+            return tmp;
+        }
+
+        protected byte[] engineGetEncoded(
+            String format) 
+            throws IOException
+        {
+            if (format.equals("RAW"))
+            {
+                return engineGetEncoded();
+            }
+            else if (format.equals("ASN.1"))
+            {
+                if (parameterVersion == -1)
+                {
+                    return new RC2CBCParameter(engineGetEncoded()).getEncoded();
+                }
+                else
+                {
+                    return new RC2CBCParameter(parameterVersion, engineGetEncoded()).getEncoded();
+                }
+            }
+
+            return null;
+        }
+
+        protected AlgorithmParameterSpec engineGetParameterSpec(
+            Class paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec == RC2ParameterSpec.class)
+            {
+                if (parameterVersion != -1)
+                {
+                    if (parameterVersion < 256)
+                    {
+                        return new RC2ParameterSpec(ekb[parameterVersion], iv);
+                    }
+                    else
+                    {
+                        return new RC2ParameterSpec(parameterVersion, iv);
+                    }
+                }
+            }
+
+            if (paramSpec == IvParameterSpec.class)
+            {
+                return new IvParameterSpec(iv);
+            }
+
+            throw new InvalidParameterSpecException("unknown parameter spec passed to RC2 parameters object.");
+        }
+
+        protected void engineInit(
+            AlgorithmParameterSpec paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec instanceof IvParameterSpec)
+            {
+                this.iv = ((IvParameterSpec)paramSpec).getIV();
+            }
+            else if (paramSpec instanceof RC2ParameterSpec)
+            {
+                int effKeyBits = ((RC2ParameterSpec)paramSpec).getEffectiveKeyBits();
+                if (effKeyBits != -1)
+                {
+                    if (effKeyBits < 256)
+                    {
+                        parameterVersion = table[effKeyBits];
+                    }
+                    else
+                    {
+                        parameterVersion = effKeyBits;
+                    }
+                }
+
+                this.iv = ((RC2ParameterSpec)paramSpec).getIV();
+            }
+            else
+            {
+                throw new InvalidParameterSpecException("IvParameterSpec or RC2ParameterSpec required to initialise a RC2 parameters algorithm parameters object");
+            }
+        }
+
+        protected void engineInit(
+            byte[] params) 
+            throws IOException
+        {
+            this.iv = new byte[params.length];
+
+            System.arraycopy(params, 0, iv, 0, iv.length);
+        }
+
+        protected void engineInit(
+            byte[] params,
+            String format) 
+            throws IOException
+        {
+            if (format.equals("RAW"))
+            {
+                engineInit(params);
+                return;
+            }
+            else if (format.equals("ASN.1"))
+            {
+                ASN1InputStream         aIn = new ASN1InputStream(params);
+                RC2CBCParameter         p = RC2CBCParameter.getInstance(aIn.readObject());
+
+                if (p.getRC2ParameterVersion() != null)
+                {
+                    parameterVersion = p.getRC2ParameterVersion().intValue();
+                }
+
+                iv = p.getIV();
+
+                return;
+            }
+
+            throw new IOException("Unknown parameters format in IV parameters object");
+        }
+
+        protected String engineToString() 
+        {
+            return "RC2 Parameters";
+        }
+    }
+
+    public static class CAST5AlgorithmParameters
+        extends JDKAlgorithmParameters
+    {
+        private byte[]  iv;
+        private int     keyLength = 128;
+
+        protected byte[] engineGetEncoded() 
+        {
+            byte[]  tmp = new byte[iv.length];
+
+            System.arraycopy(iv, 0, tmp, 0, iv.length);
+            return tmp;
+        }
+
+        protected byte[] engineGetEncoded(
+            String format) 
+            throws IOException 
+        {
+            if (format.equals("RAW"))
+            {
+                return engineGetEncoded();
+            }
+            // BEGIN android-removed
+            // else if (format.equals("ASN.1"))
+            // {
+            //     return new CAST5CBCParameters(engineGetEncoded(), keyLength).getEncoded();
+            // }
+            // END android-removed
+
+            return null;
+        }
+
+        protected AlgorithmParameterSpec engineGetParameterSpec(
+            Class paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec == IvParameterSpec.class)
+            {
+                return new IvParameterSpec(iv);
+            }
+
+            throw new InvalidParameterSpecException("unknown parameter spec passed to CAST5 parameters object.");
+        }
+
+        protected void engineInit(
+            AlgorithmParameterSpec paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec instanceof IvParameterSpec)
+            {
+                this.iv = ((IvParameterSpec)paramSpec).getIV();
+            }
+            else
+            {
+                throw new InvalidParameterSpecException("IvParameterSpec required to initialise a CAST5 parameters algorithm parameters object");
+            }
+        }
+
+        protected void engineInit(
+            byte[] params) 
+            throws IOException
+        {
+            this.iv = new byte[params.length];
+
+            System.arraycopy(params, 0, iv, 0, iv.length);
+        }
+
+        protected void engineInit(
+            byte[] params,
+            String format) 
+            throws IOException
+        {
+            if (format.equals("RAW"))
+            {
+                engineInit(params);
+                return;
+            }
+            // BEGIN android-removed
+            // else if (format.equals("ASN.1"))
+            // {
+            //     ASN1InputStream         aIn = new ASN1InputStream(params);
+            //     CAST5CBCParameters      p = CAST5CBCParameters.getInstance(aIn.readObject());
+            //
+            //     keyLength = p.getKeyLength();
+            //
+            //     iv = p.getIV();
+            //
+            //     return;
+            // }
+            // END android-removed
+
+            throw new IOException("Unknown parameters format in IV parameters object");
+        }
+
+        protected String engineToString() 
+        {
+            return "CAST5 Parameters";
+        }
+    }
+
+    public static class PKCS12PBE
+        extends JDKAlgorithmParameters
+    {
+        PKCS12PBEParams params;
+
+        protected byte[] engineGetEncoded() 
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DEROutputStream         dOut = new DEROutputStream(bOut);
+
+            try
+            {
+                dOut.writeObject(params);
+            }
+            catch (IOException e)
+            {
+                throw new RuntimeException("Oooops! " + e.toString());
+            }
+
+            return bOut.toByteArray();
+        }
+
+        protected byte[] engineGetEncoded(
+            String format) 
+        {
+            if (format.equals("ASN.1"))
+            {
+                return engineGetEncoded();
+            }
+
+            return null;
+        }
+
+        protected AlgorithmParameterSpec engineGetParameterSpec(
+            Class paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec == PBEParameterSpec.class)
+            {
+                return new PBEParameterSpec(params.getIV(),
+                                params.getIterations().intValue());
+            }
+
+            throw new InvalidParameterSpecException("unknown parameter spec passed to PKCS12 PBE parameters object.");
+        }
+
+        protected void engineInit(
+            AlgorithmParameterSpec paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (!(paramSpec instanceof PBEParameterSpec))
+            {
+                throw new InvalidParameterSpecException("PBEParameterSpec required to initialise a PKCS12 PBE parameters algorithm parameters object");
+            }
+
+            PBEParameterSpec    pbeSpec = (PBEParameterSpec)paramSpec;
+
+            this.params = new PKCS12PBEParams(pbeSpec.getSalt(),
+                                pbeSpec.getIterationCount());
+        }
+
+        protected void engineInit(
+            byte[] params) 
+            throws IOException
+        {
+            ASN1InputStream        aIn = new ASN1InputStream(params);
+
+            this.params = PKCS12PBEParams.getInstance(aIn.readObject());
+        }
+
+        protected void engineInit(
+            byte[] params,
+            String format) 
+            throws IOException
+        {
+            if (format.equals("ASN.1"))
+            {
+                engineInit(params);
+                return;
+            }
+
+            throw new IOException("Unknown parameters format in PKCS12 PBE parameters object");
+        }
+
+        protected String engineToString() 
+        {
+            return "PKCS12 PBE Parameters";
+        }
+    }
+
+    public static class DH
+        extends JDKAlgorithmParameters
+    {
+        DHParameterSpec     currentSpec;
+
+        /**
+         * Return the PKCS#3 ASN.1 structure DHParameter.
+         * <p>
+         * <pre>
+         *  DHParameter ::= SEQUENCE {
+         *                   prime INTEGER, -- p
+         *                   base INTEGER, -- g
+         *                   privateValueLength INTEGER OPTIONAL}
+         * </pre>
+         */
+        protected byte[] engineGetEncoded() 
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DEROutputStream         dOut = new DEROutputStream(bOut);
+            DHParameter             dhP = new DHParameter(currentSpec.getP(), currentSpec.getG(), currentSpec.getL());
+
+            try
+            {
+                dOut.writeObject(dhP);
+                dOut.close();
+            }
+            catch (IOException e)
+            {
+                throw new RuntimeException("Error encoding DHParameters");
+            }
+
+            return bOut.toByteArray();
+        }
+
+        protected byte[] engineGetEncoded(
+            String format) 
+        {
+            if (format.equalsIgnoreCase("X.509")
+                    || format.equalsIgnoreCase("ASN.1"))
+            {
+                return engineGetEncoded();
+            }
+
+            return null;
+        }
+
+        protected AlgorithmParameterSpec engineGetParameterSpec(
+            Class paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec == DHParameterSpec.class)
+            {
+                return currentSpec;
+            }
+
+            throw new InvalidParameterSpecException("unknown parameter spec passed to DH parameters object.");
+        }
+
+        protected void engineInit(
+            AlgorithmParameterSpec paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (!(paramSpec instanceof DHParameterSpec))
+            {
+                throw new InvalidParameterSpecException("DHParameterSpec required to initialise a Diffie-Hellman algorithm parameters object");
+            }
+
+            this.currentSpec = (DHParameterSpec)paramSpec;
+        }
+
+        protected void engineInit(
+            byte[] params) 
+            throws IOException
+        {
+            ASN1InputStream        aIn = new ASN1InputStream(params);
+
+            try
+            {
+                DHParameter dhP = new DHParameter((ASN1Sequence)aIn.readObject());
+
+                if (dhP.getL() != null)
+                {
+                    currentSpec = new DHParameterSpec(dhP.getP(), dhP.getG(), dhP.getL().intValue());
+                }
+                else
+                {
+                    currentSpec = new DHParameterSpec(dhP.getP(), dhP.getG());
+                }
+            }
+            catch (ClassCastException e)
+            {
+                throw new IOException("Not a valid DH Parameter encoding.");
+            }
+            catch (ArrayIndexOutOfBoundsException e)
+            {
+                throw new IOException("Not a valid DH Parameter encoding.");
+            }
+        }
+
+        protected void engineInit(
+            byte[] params,
+            String format) 
+            throws IOException
+        {
+            if (format.equalsIgnoreCase("X.509")
+                    || format.equalsIgnoreCase("ASN.1"))
+            {
+                engineInit(params);
+            }
+            else
+            {
+                throw new IOException("Unknown parameter format " + format);
+            }
+        }
+
+        protected String engineToString() 
+        {
+            return "Diffie-Hellman Parameters";
+        }
+    }
+
+    public static class DSA
+        extends JDKAlgorithmParameters
+    {
+        DSAParameterSpec     currentSpec;
+
+        /**
+         * Return the X.509 ASN.1 structure DSAParameter.
+         * <p>
+         * <pre>
+         *  DSAParameter ::= SEQUENCE {
+         *                   prime INTEGER, -- p
+         *                   subprime INTEGER, -- q
+         *                   base INTEGER, -- g}
+         * </pre>
+         */
+        protected byte[] engineGetEncoded() 
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DEROutputStream         dOut = new DEROutputStream(bOut);
+            DSAParameter            dsaP = new DSAParameter(currentSpec.getP(), currentSpec.getQ(), currentSpec.getG());
+
+            try
+            {
+                dOut.writeObject(dsaP);
+                dOut.close();
+            }
+            catch (IOException e)
+            {
+                throw new RuntimeException("Error encoding DSAParameters");
+            }
+
+            return bOut.toByteArray();
+        }
+
+        protected byte[] engineGetEncoded(
+            String format) 
+        {
+            if (format.equalsIgnoreCase("X.509")
+                    || format.equalsIgnoreCase("ASN.1"))
+            {
+                return engineGetEncoded();
+            }
+
+            return null;
+        }
+
+        protected AlgorithmParameterSpec engineGetParameterSpec(
+            Class paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec == DSAParameterSpec.class)
+            {
+                return currentSpec;
+            }
+
+            throw new InvalidParameterSpecException("unknown parameter spec passed to DSA parameters object.");
+        }
+
+        protected void engineInit(
+            AlgorithmParameterSpec paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (!(paramSpec instanceof DSAParameterSpec))
+            {
+                throw new InvalidParameterSpecException("DSAParameterSpec required to initialise a DSA algorithm parameters object");
+            }
+
+            this.currentSpec = (DSAParameterSpec)paramSpec;
+        }
+
+        protected void engineInit(
+            byte[] params) 
+            throws IOException
+        {
+            ASN1InputStream        aIn = new ASN1InputStream(params);
+
+            try
+            {
+                DSAParameter dsaP = new DSAParameter((ASN1Sequence)aIn.readObject());
+
+                currentSpec = new DSAParameterSpec(dsaP.getP(), dsaP.getQ(), dsaP.getG());
+            }
+            catch (ClassCastException e)
+            {
+                throw new IOException("Not a valid DSA Parameter encoding.");
+            }
+            catch (ArrayIndexOutOfBoundsException e)
+            {
+                throw new IOException("Not a valid DSA Parameter encoding.");
+            }
+        }
+
+        protected void engineInit(
+            byte[] params,
+            String format) 
+            throws IOException
+        {
+            if (format.equalsIgnoreCase("X.509")
+                    || format.equalsIgnoreCase("ASN.1"))
+            {
+                engineInit(params);
+            }
+            else
+            {
+                throw new IOException("Unknown parameter format " + format);
+            }
+        }
+
+        protected String engineToString() 
+        {
+            return "DSA Parameters";
+        }
+    }
+    
+// BEGIN android-removed
+//    public static class GOST3410
+//        extends JDKAlgorithmParameters
+//    {
+//        GOST3410ParameterSpec     currentSpec;
+//        
+//        /**
+//         * Return the X.509 ASN.1 structure GOST3410Parameter.
+//         * <p>
+//         * <pre>
+//         *  GOST3410Parameter ::= SEQUENCE {
+//         *                   prime INTEGER, -- p
+//         *                   subprime INTEGER, -- q
+//         *                   base INTEGER, -- a}
+//         * </pre>
+//         */
+//        protected byte[] engineGetEncoded()
+//        {
+//            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+//            DEROutputStream         dOut = new DEROutputStream(bOut);
+//            GOST3410PublicKeyAlgParameters       gost3410P = new GOST3410PublicKeyAlgParameters(new DERObjectIdentifier(currentSpec.getPublicKeyParamSetOID()), new DERObjectIdentifier(currentSpec.getDigestParamSetOID()), new DERObjectIdentifier(currentSpec.getEncryptionParamSetOID()));
+//            
+//            try
+//            {
+//                dOut.writeObject(gost3410P);
+//                dOut.close();
+//            }
+//            catch (IOException e)
+//            {
+//                throw new RuntimeException("Error encoding GOST3410Parameters");
+//            }
+//            
+//            return bOut.toByteArray();
+//        }
+//        
+//        protected byte[] engineGetEncoded(
+//                String format)
+//        {
+//            if (format.equalsIgnoreCase("X.509")
+//                    || format.equalsIgnoreCase("ASN.1"))
+//            {
+//                return engineGetEncoded();
+//            }
+//            
+//            return null;
+//        }
+//        
+//        protected AlgorithmParameterSpec engineGetParameterSpec(
+//                Class paramSpec)
+//        throws InvalidParameterSpecException
+//        {
+//            if (paramSpec == GOST3410PublicKeyParameterSetSpec.class)
+//            {
+//                return currentSpec;
+//            }
+//            
+//            throw new InvalidParameterSpecException("unknown parameter spec passed to GOST3410 parameters object.");
+//        }
+//        
+//        protected void engineInit(
+//                AlgorithmParameterSpec paramSpec)
+//        throws InvalidParameterSpecException
+//        {
+//            if (!(paramSpec instanceof GOST3410ParameterSpec))
+//            {
+//                throw new InvalidParameterSpecException("GOST3410ParameterSpec required to initialise a GOST3410 algorithm parameters object");
+//            }
+//            
+//            this.currentSpec = (GOST3410ParameterSpec)paramSpec;
+//        }
+//        
+//        protected void engineInit(
+//                byte[] params)
+//        throws IOException
+//        {
+//            ASN1InputStream        dIn = new ASN1InputStream(params);
+//            
+//            try
+//            {
+//                GOST3410PublicKeyAlgParameters gost3410P = new GOST3410PublicKeyAlgParameters((ASN1Sequence)dIn.readObject());
+//                
+//                currentSpec = new GOST3410ParameterSpec(gost3410P.getPublicKeyParamSet().getId(), gost3410P.getDigestParamSet().getId(), gost3410P.getEncryptionParamSet().getId());
+//            }
+//            catch (ClassCastException e)
+//            {
+//                throw new IOException("Not a valid GOST3410 Parameter encoding.");
+//            }
+//            catch (ArrayIndexOutOfBoundsException e)
+//            {
+//                throw new IOException("Not a valid GOST3410 Parameter encoding.");
+//            }
+//        }
+//        
+//        protected void engineInit(
+//                byte[] params,
+//                String format)
+//        throws IOException
+//        {
+//            if (format.equalsIgnoreCase("X.509")
+//                    || format.equalsIgnoreCase("ASN.1"))
+//            {
+//                engineInit(params);
+//            }
+//            else
+//            {
+//                throw new IOException("Unknown parameter format " + format);
+//            }
+//        }
+//        
+//        protected String engineToString()
+//        {
+//            return "GOST3410 Parameters";
+//        }
+//    }
+//
+//    public static class ElGamal
+//        extends JDKAlgorithmParameters
+//    {
+//        ElGamalParameterSpec     currentSpec;
+//
+//        /**
+//         * Return the X.509 ASN.1 structure ElGamalParameter.
+//         * <p>
+//         * <pre>
+//         *  ElGamalParameter ::= SEQUENCE {
+//         *                   prime INTEGER, -- p
+//         *                   base INTEGER, -- g}
+//         * </pre>
+//         */
+//        protected byte[] engineGetEncoded() 
+//        {
+//            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+//            DEROutputStream         dOut = new DEROutputStream(bOut);
+//            ElGamalParameter        elP = new ElGamalParameter(currentSpec.getP(), currentSpec.getG());
+//
+//            try
+//            {
+//                dOut.writeObject(elP);
+//                dOut.close();
+//            }
+//            catch (IOException e)
+//            {
+//                throw new RuntimeException("Error encoding ElGamalParameters");
+//            }
+//
+//            return bOut.toByteArray();
+//        }
+//
+//        protected byte[] engineGetEncoded(
+//            String format) 
+//        {
+//            if (format.equalsIgnoreCase("X.509")
+//                    || format.equalsIgnoreCase("ASN.1"))
+//            {
+//                return engineGetEncoded();
+//            }
+//
+//            return null;
+//        }
+//
+//        protected AlgorithmParameterSpec engineGetParameterSpec(
+//            Class paramSpec) 
+//            throws InvalidParameterSpecException
+//        {
+//            if (paramSpec == ElGamalParameterSpec.class)
+//            {
+//                return currentSpec;
+//            }
+//            else if (paramSpec == DHParameterSpec.class)
+//            {
+//                return new DHParameterSpec(currentSpec.getP(), currentSpec.getG());
+//            }
+//
+//            throw new InvalidParameterSpecException("unknown parameter spec passed to ElGamal parameters object.");
+//        }
+//
+//        protected void engineInit(
+//            AlgorithmParameterSpec paramSpec) 
+//            throws InvalidParameterSpecException
+//        {
+//            if (!(paramSpec instanceof ElGamalParameterSpec) && !(paramSpec instanceof DHParameterSpec))
+//            {
+//                throw new InvalidParameterSpecException("DHParameterSpec required to initialise a ElGamal algorithm parameters object");
+//            }
+//
+//            if (paramSpec instanceof ElGamalParameterSpec)
+//            {
+//                this.currentSpec = (ElGamalParameterSpec)paramSpec;
+//            }
+//            else
+//            {
+//                DHParameterSpec s = (DHParameterSpec)paramSpec;
+//                
+//                this.currentSpec = new ElGamalParameterSpec(s.getP(), s.getG());
+//            }
+//        }
+//
+//        protected void engineInit(
+//            byte[] params) 
+//            throws IOException
+//        {
+//            ASN1InputStream        aIn = new ASN1InputStream(params);
+//
+//            try
+//            {
+//                ElGamalParameter elP = new ElGamalParameter((ASN1Sequence)aIn.readObject());
+//
+//                currentSpec = new ElGamalParameterSpec(elP.getP(), elP.getG());
+//            }
+//            catch (ClassCastException e)
+//            {
+//                throw new IOException("Not a valid ElGamal Parameter encoding.");
+//            }
+//            catch (ArrayIndexOutOfBoundsException e)
+//            {
+//                throw new IOException("Not a valid ElGamal Parameter encoding.");
+//            }
+//        }
+//
+//        protected void engineInit(
+//            byte[] params,
+//            String format) 
+//            throws IOException
+//        {
+//            if (format.equalsIgnoreCase("X.509")
+//                    || format.equalsIgnoreCase("ASN.1"))
+//            {
+//                engineInit(params);
+//            }
+//            else
+//            {
+//                throw new IOException("Unknown parameter format " + format);
+//            }
+//        }
+//
+//        protected String engineToString() 
+//        {
+//            return "ElGamal Parameters";
+//        }
+//    }
+// END android-removed
+
+    public static class IES
+        extends JDKAlgorithmParameters
+    {
+        IESParameterSpec     currentSpec;
+
+        /**
+         * in the abscence of a standard way of doing it this will do for
+         * now...
+         */
+        protected byte[] engineGetEncoded() 
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DEROutputStream         dOut = new DEROutputStream(bOut);
+
+            try
+            {
+                ASN1EncodableVector    v = new ASN1EncodableVector();
+
+                v.add(new DEROctetString(currentSpec.getDerivationV()));
+                v.add(new DEROctetString(currentSpec.getEncodingV()));
+                v.add(new DERInteger(currentSpec.getMacKeySize()));
+
+                dOut.writeObject(new DERSequence(v));
+                dOut.close();
+            }
+            catch (IOException e)
+            {
+                throw new RuntimeException("Error encoding IESParameters");
+            }
+
+            return bOut.toByteArray();
+        }
+
+        protected byte[] engineGetEncoded(
+            String format) 
+        {
+            if (format.equalsIgnoreCase("X.509")
+                    || format.equalsIgnoreCase("ASN.1"))
+            {
+                return engineGetEncoded();
+            }
+
+            return null;
+        }
+
+        protected AlgorithmParameterSpec engineGetParameterSpec(
+            Class paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec == IESParameterSpec.class)
+            {
+                return currentSpec;
+            }
+
+            throw new InvalidParameterSpecException("unknown parameter spec passed to ElGamal parameters object.");
+        }
+
+        protected void engineInit(
+            AlgorithmParameterSpec paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (!(paramSpec instanceof IESParameterSpec))
+            {
+                throw new InvalidParameterSpecException("IESParameterSpec required to initialise a IES algorithm parameters object");
+            }
+
+            this.currentSpec = (IESParameterSpec)paramSpec;
+        }
+
+        protected void engineInit(
+            byte[] params) 
+            throws IOException
+        {
+            ASN1InputStream        aIn = new ASN1InputStream(params);
+
+            try
+            {
+                ASN1Sequence    s = (ASN1Sequence)aIn.readObject();
+
+                this.currentSpec = new IESParameterSpec(
+                                        ((ASN1OctetString)s.getObjectAt(0)).getOctets(),
+                                        ((ASN1OctetString)s.getObjectAt(0)).getOctets(),
+                                        ((DERInteger)s.getObjectAt(0)).getValue().intValue());
+            }
+            catch (ClassCastException e)
+            {
+                throw new IOException("Not a valid IES Parameter encoding.");
+            }
+            catch (ArrayIndexOutOfBoundsException e)
+            {
+                throw new IOException("Not a valid IES Parameter encoding.");
+            }
+        }
+
+        protected void engineInit(
+            byte[] params,
+            String format) 
+            throws IOException
+        {
+            if (format.equalsIgnoreCase("X.509")
+                    || format.equalsIgnoreCase("ASN.1"))
+            {
+                engineInit(params);
+            }
+            else
+            {
+                throw new IOException("Unknown parameter format " + format);
+            }
+        }
+
+        protected String engineToString() 
+        {
+            return "IES Parameters";
+        }
+    }
+    
+    public static class OAEP
+        extends JDKAlgorithmParameters
+    {
+        OAEPParameterSpec     currentSpec;
+    
+        /**
+         * Return the PKCS#1 ASN.1 structure RSA-ES-OAEP-params.
+         */
+        protected byte[] engineGetEncoded() 
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DEROutputStream         dOut = new DEROutputStream(bOut);
+            // BEGIN android-changed
+            AlgorithmIdentifier     hashAlgorithm = new AlgorithmIdentifier(
+                                                            JCEDigestUtil.getOID(currentSpec.getDigestAlgorithm()),
+                                                            DERNull.THE_ONE);
+            MGF1ParameterSpec       mgfSpec = (MGF1ParameterSpec)currentSpec.getMGFParameters();
+            AlgorithmIdentifier     maskGenAlgorithm = new AlgorithmIdentifier(
+                                                            PKCSObjectIdentifiers.id_mgf1, 
+                                                            new AlgorithmIdentifier(JCEDigestUtil.getOID(mgfSpec.getDigestAlgorithm()), DERNull.THE_ONE));
+            // END android-changed
+            PSource.PSpecified      pSource = (PSource.PSpecified)currentSpec.getPSource();
+            AlgorithmIdentifier     pSourceAlgorithm = new AlgorithmIdentifier(
+                                                            PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(pSource.getValue()));
+            RSAESOAEPparams         oaepP = new RSAESOAEPparams(hashAlgorithm, maskGenAlgorithm, pSourceAlgorithm);
+    
+            try
+            {
+                dOut.writeObject(oaepP);
+                dOut.close();
+            }
+            catch (IOException e)
+            {
+                throw new RuntimeException("Error encoding OAEPParameters");
+            }
+    
+            return bOut.toByteArray();
+        }
+    
+        protected byte[] engineGetEncoded(
+            String format) 
+        {
+            if (format.equalsIgnoreCase("X.509")
+                    || format.equalsIgnoreCase("ASN.1"))
+            {
+                return engineGetEncoded();
+            }
+    
+            return null;
+        }
+    
+        protected AlgorithmParameterSpec engineGetParameterSpec(
+            Class paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec == OAEPParameterSpec.class && currentSpec instanceof OAEPParameterSpec)
+            {
+                return currentSpec;
+            }
+    
+            throw new InvalidParameterSpecException("unknown parameter spec passed to OAEP parameters object.");
+        }
+    
+        protected void engineInit(
+            AlgorithmParameterSpec paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (!(paramSpec instanceof OAEPParameterSpec))
+            {
+                throw new InvalidParameterSpecException("OAEPParameterSpec required to initialise an OAEP algorithm parameters object");
+            }
+    
+            this.currentSpec = (OAEPParameterSpec)paramSpec;
+        }
+    
+        protected void engineInit(
+            byte[] params) 
+            throws IOException
+        {
+            ASN1InputStream        aIn = new ASN1InputStream(params);
+    
+            try
+            {
+                RSAESOAEPparams oaepP = new RSAESOAEPparams((ASN1Sequence)aIn.readObject());
+    
+                currentSpec = new OAEPParameterSpec(
+                                       oaepP.getHashAlgorithm().getObjectId().getId(), 
+                                       oaepP.getMaskGenAlgorithm().getObjectId().getId(), 
+                                       new MGF1ParameterSpec(AlgorithmIdentifier.getInstance(oaepP.getMaskGenAlgorithm().getParameters()).getObjectId().getId()),
+                                       new PSource.PSpecified(ASN1OctetString.getInstance(oaepP.getPSourceAlgorithm().getParameters()).getOctets()));
+            }
+            catch (ClassCastException e)
+            {
+                throw new IOException("Not a valid OAEP Parameter encoding.");
+            }
+            catch (ArrayIndexOutOfBoundsException e)
+            {
+                throw new IOException("Not a valid OAEP Parameter encoding.");
+            }
+        }
+    
+        protected void engineInit(
+            byte[] params,
+            String format) 
+            throws IOException
+        {
+            if (format.equalsIgnoreCase("X.509")
+                    || format.equalsIgnoreCase("ASN.1"))
+            {
+                engineInit(params);
+            }
+            else
+            {
+                throw new IOException("Unknown parameter format " + format);
+            }
+        }
+    
+        protected String engineToString() 
+        {
+            return "OAEP Parameters";
+        }
+    }
+    
+    public static class PSS
+        extends JDKAlgorithmParameters
+    {  
+        PSSParameterSpec     currentSpec;
+    
+        /**
+         * Return the PKCS#1 ASN.1 structure RSA-ES-OAEP-params.
+         */
+        protected byte[] engineGetEncoded() 
+            throws IOException
+        {
+            PSSParameterSpec    pssSpec = (PSSParameterSpec)currentSpec;
+            // BEGIN android-changed
+            AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(
+                                                JCEDigestUtil.getOID(pssSpec.getDigestAlgorithm()),
+                                                DERNull.THE_ONE);
+            MGF1ParameterSpec   mgfSpec = (MGF1ParameterSpec)pssSpec.getMGFParameters();
+            AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier(
+                                                PKCSObjectIdentifiers.id_mgf1, 
+                                                new AlgorithmIdentifier(JCEDigestUtil.getOID(mgfSpec.getDigestAlgorithm()), DERNull.THE_ONE));
+            // END android-changed
+            RSASSAPSSparams     pssP = new RSASSAPSSparams(hashAlgorithm, maskGenAlgorithm, new DERInteger(pssSpec.getSaltLength()), new DERInteger(pssSpec.getTrailerField()));
+            
+            return pssP.getEncoded("DER");
+        }
+    
+        protected byte[] engineGetEncoded(
+            String format) 
+            throws IOException
+        {
+            if (format.equalsIgnoreCase("X.509")
+                    || format.equalsIgnoreCase("ASN.1"))
+            {
+                return engineGetEncoded();
+            }
+    
+            return null;
+        }
+    
+        protected AlgorithmParameterSpec engineGetParameterSpec(
+            Class paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (paramSpec == PSSParameterSpec.class && currentSpec instanceof PSSParameterSpec)
+            {
+                return currentSpec;
+            }
+    
+            throw new InvalidParameterSpecException("unknown parameter spec passed to PSS parameters object.");
+        }
+    
+        protected void engineInit(
+            AlgorithmParameterSpec paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            if (!(paramSpec instanceof PSSParameterSpec))
+            {
+                throw new InvalidParameterSpecException("PSSParameterSpec required to initialise an PSS algorithm parameters object");
+            }
+    
+            this.currentSpec = (PSSParameterSpec)paramSpec;
+        }
+    
+        protected void engineInit(
+            byte[] params) 
+            throws IOException
+        {
+            ASN1InputStream        aIn = new ASN1InputStream(params);
+    
+            try
+            {
+                RSASSAPSSparams pssP = new RSASSAPSSparams((ASN1Sequence)aIn.readObject());
+    
+                currentSpec = new PSSParameterSpec(
+                                       pssP.getHashAlgorithm().getObjectId().getId(), 
+                                       pssP.getMaskGenAlgorithm().getObjectId().getId(), 
+                                       new MGF1ParameterSpec(AlgorithmIdentifier.getInstance(pssP.getMaskGenAlgorithm().getParameters()).getObjectId().getId()),
+                                       pssP.getSaltLength().getValue().intValue(),
+                                       pssP.getTrailerField().getValue().intValue());
+            }
+            catch (ClassCastException e)
+            {
+                throw new IOException("Not a valid PSS Parameter encoding.");
+            }
+            catch (ArrayIndexOutOfBoundsException e)
+            {
+                throw new IOException("Not a valid PSS Parameter encoding.");
+            }
+        }
+    
+        protected void engineInit(
+            byte[] params,
+            String format) 
+            throws IOException
+        {
+            if (format.equalsIgnoreCase("X.509")
+                    || format.equalsIgnoreCase("ASN.1"))
+            {
+                engineInit(params);
+            }
+            else
+            {
+                throw new IOException("Unknown parameter format " + format);
+            }
+        }
+    
+        protected String engineToString() 
+        {
+            return "PSS Parameters";
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKDSAPrivateKey.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKDSAPrivateKey.java
new file mode 100644
index 0000000..111ab5b
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKDSAPrivateKey.java
@@ -0,0 +1,139 @@
+package org.bouncycastle.jce.provider;
+
+import java.math.BigInteger;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.DSAPrivateKeySpec;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.DSAParameter;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+public class JDKDSAPrivateKey
+    implements DSAPrivateKey, PKCS12BagAttributeCarrier
+{
+    BigInteger          x;
+    DSAParams           dsaSpec;
+
+    private Hashtable   pkcs12Attributes = new Hashtable();
+    private Vector      pkcs12Ordering = new Vector();
+
+    protected JDKDSAPrivateKey()
+    {
+    }
+
+    JDKDSAPrivateKey(
+        DSAPrivateKey    key)
+    {
+        this.x = key.getX();
+        this.dsaSpec = key.getParams();
+    }
+
+    JDKDSAPrivateKey(
+        DSAPrivateKeySpec    spec)
+    {
+        this.x = spec.getX();
+        this.dsaSpec = new DSAParameterSpec(spec.getP(), spec.getQ(), spec.getG());
+    }
+
+    JDKDSAPrivateKey(
+        PrivateKeyInfo  info)
+    {
+        DSAParameter    params = new DSAParameter((ASN1Sequence)info.getAlgorithmId().getParameters());
+        DERInteger      derX = (DERInteger)info.getPrivateKey();
+
+        this.x = derX.getValue();
+        this.dsaSpec = new DSAParameterSpec(params.getP(), params.getQ(), params.getG());
+    }
+
+    JDKDSAPrivateKey(
+        DSAPrivateKeyParameters  params)
+    {
+        this.x = params.getX();
+        this.dsaSpec = new DSAParameterSpec(params.getParameters().getP(), params.getParameters().getQ(), params.getParameters().getG());
+    }
+
+    public String getAlgorithm()
+    {
+        return "DSA";
+    }
+
+    /**
+     * return the encoding format we produce in getEncoded().
+     *
+     * @return the string "PKCS#8"
+     */
+    public String getFormat()
+    {
+        return "PKCS#8";
+    }
+
+    /**
+     * Return a PKCS8 representation of the key. The sequence returned
+     * represents a full PrivateKeyInfo object.
+     *
+     * @return a PKCS8 representation of the key.
+     */
+    public byte[] getEncoded()
+    {
+        PrivateKeyInfo          info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG()).getDERObject()), new DERInteger(getX()));
+
+        return info.getDEREncoded();
+    }
+
+    public DSAParams getParams()
+    {
+        return dsaSpec;
+    }
+
+    public BigInteger getX()
+    {
+        return x;
+    }
+
+    public boolean equals(
+        Object o)
+    {
+        if (!(o instanceof DSAPrivateKey))
+        {
+            return false;
+        }
+        
+        DSAPrivateKey other = (DSAPrivateKey)o;
+        
+        return this.getX().equals(other.getX()) 
+            && this.getParams().getG().equals(other.getParams().getG()) 
+            && this.getParams().getP().equals(other.getParams().getP()) 
+            && this.getParams().getQ().equals(other.getParams().getQ());
+    }
+    
+    public void setBagAttribute(
+        DERObjectIdentifier oid,
+        DEREncodable        attribute)
+    {
+        pkcs12Attributes.put(oid, attribute);
+        pkcs12Ordering.addElement(oid);
+    }
+
+    public DEREncodable getBagAttribute(
+        DERObjectIdentifier oid)
+    {
+        return (DEREncodable)pkcs12Attributes.get(oid);
+    }
+
+    public Enumeration getBagAttributeKeys()
+    {
+        return pkcs12Ordering.elements();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKDSAPublicKey.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKDSAPublicKey.java
new file mode 100644
index 0000000..56e8470
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKDSAPublicKey.java
@@ -0,0 +1,125 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.DSAPublicKeySpec;
+
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.DSAParameter;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
+
+public class JDKDSAPublicKey
+    implements DSAPublicKey
+{
+    private BigInteger      y;
+    private DSAParams       dsaSpec;
+
+    JDKDSAPublicKey(
+        DSAPublicKeySpec    spec)
+    {
+        this.y = spec.getY();
+        this.dsaSpec = new DSAParameterSpec(spec.getP(), spec.getQ(), spec.getG());
+    }
+
+    JDKDSAPublicKey(
+        DSAPublicKey    key)
+    {
+        this.y = key.getY();
+        this.dsaSpec = key.getParams();
+    }
+
+    JDKDSAPublicKey(
+        DSAPublicKeyParameters  params)
+    {
+        this.y = params.getY();
+        this.dsaSpec = new DSAParameterSpec(params.getParameters().getP(), params.getParameters().getQ(), params.getParameters().getG());
+    }
+
+    JDKDSAPublicKey(
+        BigInteger        y,
+        DSAParameterSpec  dsaSpec)
+    {
+        this.y = y;
+        this.dsaSpec = dsaSpec;
+    }
+
+    JDKDSAPublicKey(
+        SubjectPublicKeyInfo    info)
+    {
+        DSAParameter            params = new DSAParameter((ASN1Sequence)info.getAlgorithmId().getParameters());
+        DERInteger              derY = null;
+
+        try
+        {
+            derY = (DERInteger)info.getPublicKey();
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("invalid info structure in DSA public key");
+        }
+
+        this.y = derY.getValue();
+        this.dsaSpec = new DSAParameterSpec(params.getP(), params.getQ(), params.getG());
+    }
+
+    public String getAlgorithm()
+    {
+        return "DSA";
+    }
+
+    public String getFormat()
+    {
+        return "X.509";
+    }
+
+    public byte[] getEncoded()
+    {
+        SubjectPublicKeyInfo    info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG()).getDERObject()), new DERInteger(y));
+
+        return info.getDEREncoded();
+    }
+
+    public DSAParams getParams()
+    {
+        return dsaSpec;
+    }
+
+    public BigInteger getY()
+    {
+        return y;
+    }
+
+    public String toString()
+    {
+        StringBuffer    buf = new StringBuffer();
+        String          nl = System.getProperty("line.separator");
+
+        buf.append("DSA Public Key").append(nl);
+        buf.append("            y: ").append(this.getY().toString(16)).append(nl);
+
+        return buf.toString();
+    }
+    
+    public boolean equals(
+        Object o)
+    {
+        if (!(o instanceof DSAPublicKey))
+        {
+            return false;
+        }
+        
+        DSAPublicKey other = (DSAPublicKey)o;
+        
+        return this.getY().equals(other.getY()) 
+            && this.getParams().getG().equals(other.getParams().getG()) 
+            && this.getParams().getP().equals(other.getParams().getP()) 
+            && this.getParams().getQ().equals(other.getParams().getQ());
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKDSASigner.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKDSASigner.java
new file mode 100644
index 0000000..9a5eb66
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKDSASigner.java
@@ -0,0 +1,426 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.interfaces.DSAKey;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DSA;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.digests.SHA224Digest;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.digests.SHA384Digest;
+import org.bouncycastle.crypto.digests.SHA512Digest;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.crypto.signers.DSASigner;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.signers.ECDSASigner;
+// import org.bouncycastle.crypto.signers.ECNRSigner;
+// import org.bouncycastle.jce.interfaces.ECKey;
+// import org.bouncycastle.jce.interfaces.ECPublicKey;
+// import org.bouncycastle.jce.interfaces.GOST3410Key;
+// END android-removed
+
+public class JDKDSASigner
+    extends Signature implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+    private Digest                  digest;
+    private DSA                     signer;
+    private SecureRandom            random;
+
+    protected JDKDSASigner(
+        String                  name,
+        Digest                  digest,
+        DSA                     signer)
+    {
+        super(name);
+
+        this.digest = digest;
+        this.signer = signer;
+    }
+
+    protected void engineInitVerify(
+        PublicKey   publicKey)
+        throws InvalidKeyException
+    {
+        CipherParameters    param = null;
+
+        // BEGIN android-removed
+        // if (publicKey instanceof ECPublicKey)
+        // {
+        //     param = ECUtil.generatePublicKeyParameter(publicKey);
+        // }
+        // else if (publicKey instanceof GOST3410Key)
+        // {
+        //     param = GOST3410Util.generatePublicKeyParameter(publicKey);
+        // }
+        // else if (publicKey instanceof DSAKey)
+        // END android-removed
+        // BEGIN android-added
+        if (publicKey instanceof DSAKey)
+        // END android-added
+        {
+            param = DSAUtil.generatePublicKeyParameter(publicKey);
+        }
+        else
+        {
+            try
+            {
+                byte[]  bytes = publicKey.getEncoded();
+
+                publicKey = JDKKeyFactory.createPublicKeyFromDERStream(bytes);
+
+                // BEGIN android-removed
+                // if (publicKey instanceof ECPublicKey)
+                // {
+                //     param = ECUtil.generatePublicKeyParameter(publicKey);
+                // }
+                // else if (publicKey instanceof DSAKey)
+                // END android-removed
+                // BEGIN android-added
+                if (publicKey instanceof DSAKey)
+                // END android-added
+                {
+                    param = DSAUtil.generatePublicKeyParameter(publicKey);
+                }
+                else
+                {
+                    throw new InvalidKeyException("can't recognise key type in DSA based signer");
+                }
+            }
+            catch (Exception e)
+            {
+                throw new InvalidKeyException("can't recognise key type in DSA based signer");
+            }
+        }
+
+        digest.reset();
+        signer.init(false, param);
+    }
+
+    protected void engineInitSign(
+        PrivateKey      privateKey,
+        SecureRandom    random)
+        throws InvalidKeyException
+    {
+        this.random = random;
+        engineInitSign(privateKey);
+    }
+
+    protected void engineInitSign(
+        PrivateKey  privateKey)
+        throws InvalidKeyException
+    {
+        CipherParameters    param = null;
+
+        // BEGIN android-removed
+        // if (privateKey instanceof ECKey)
+        // {
+        //     param = ECUtil.generatePrivateKeyParameter(privateKey);
+        // }
+        // else if (privateKey instanceof GOST3410Key)
+        // {
+        //     param = GOST3410Util.generatePrivateKeyParameter(privateKey);
+        // }
+        // else
+        // {
+        // END android-removed
+            param = DSAUtil.generatePrivateKeyParameter(privateKey);
+        // BEGIN android-removed
+        // }
+        // END android-removed
+
+        digest.reset();
+
+        if (random != null)
+        {
+            signer.init(true, new ParametersWithRandom(param, random));
+        }
+        else
+        {
+            signer.init(true, param);
+        }
+    }
+
+    protected void engineUpdate(
+        byte    b)
+        throws SignatureException
+    {
+        digest.update(b);
+    }
+
+    protected void engineUpdate(
+        byte[]  b,
+        int     off,
+        int     len) 
+        throws SignatureException
+    {
+        digest.update(b, off, len);
+    }
+
+    protected byte[] engineSign()
+        throws SignatureException
+    {
+        byte[]  hash = new byte[digest.getDigestSize()];
+
+        digest.doFinal(hash, 0);
+
+        try
+        {
+            BigInteger[]    sig = signer.generateSignature(hash);
+
+            return derEncode(sig[0], sig[1]);
+        }
+        catch (Exception e)
+        {
+            throw new SignatureException(e.toString());
+        }
+    }
+
+    protected boolean engineVerify(
+        byte[]  sigBytes) 
+        throws SignatureException
+    {
+        byte[]  hash = new byte[digest.getDigestSize()];
+
+        digest.doFinal(hash, 0);
+
+        BigInteger[]    sig;
+
+        try
+        {
+            sig = derDecode(sigBytes);
+        }
+        catch (Exception e)
+        {
+            throw new SignatureException("error decoding signature bytes.");
+        }
+
+        return signer.verifySignature(hash, sig[0], sig[1]);
+    }
+
+    protected void engineSetParameter(
+        AlgorithmParameterSpec params)
+    {
+        throw new UnsupportedOperationException("engineSetParameter unsupported");
+    }
+
+    /**
+     * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+     */
+    protected void engineSetParameter(
+        String  param,
+        Object  value)
+    {
+        throw new UnsupportedOperationException("engineSetParameter unsupported");
+    }
+
+    /**
+     * @deprecated
+     */
+    protected Object engineGetParameter(
+        String      param)
+    {
+        throw new UnsupportedOperationException("engineSetParameter unsupported");
+    }
+
+    private byte[] derEncode(
+        BigInteger  r,
+        BigInteger  s)
+        throws IOException
+    {
+        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+        DEROutputStream         dOut = new DEROutputStream(bOut);
+        ASN1EncodableVector     v = new ASN1EncodableVector();
+
+        v.add(new DERInteger(r));
+        v.add(new DERInteger(s));
+
+        dOut.writeObject(new DERSequence(v));
+
+        return bOut.toByteArray();
+    }
+
+    private BigInteger[] derDecode(
+        byte[]  encoding)
+        throws IOException
+    {
+        ASN1InputStream         aIn = new ASN1InputStream(encoding);
+        ASN1Sequence            s = (ASN1Sequence)aIn.readObject();
+
+        BigInteger[]            sig = new BigInteger[2];
+
+        sig[0] = ((DERInteger)s.getObjectAt(0)).getValue();
+        sig[1] = ((DERInteger)s.getObjectAt(1)).getValue();
+
+        return sig;
+    }
+
+    static public class stdDSA
+        extends JDKDSASigner
+    {
+        public stdDSA()
+        {
+            super("SHA1withDSA", new SHA1Digest(), new DSASigner());
+        }
+    }
+
+    static public class noneDSA
+        extends JDKDSASigner
+    {
+        public noneDSA()
+        {
+            super("NONEwithDSA", new NullDigest(), new DSASigner());
+        }
+    }
+    
+// BEGIN android-removed
+//    static public class ecDSA
+//        extends JDKDSASigner
+//    {
+//        public ecDSA()
+//        {
+//            super("SHA1withECDSA", new SHA1Digest(), new ECDSASigner());
+//        }
+//    }
+//    
+//    static public class ecDSA224
+//        extends JDKDSASigner
+//    {
+//        public ecDSA224()
+//        {
+//            super("SHA224withECDSA", new SHA224Digest(), new ECDSASigner());
+//        }
+//    }
+//    
+//    static public class ecDSA256
+//        extends JDKDSASigner
+//    {
+//        public ecDSA256()
+//        {
+//            super("SHA256withECDSA", new SHA256Digest(), new ECDSASigner());
+//        }
+//    }
+//    
+//    static public class ecDSA384
+//        extends JDKDSASigner
+//    {
+//        public ecDSA384()
+//        {
+//            super("SHA384withECDSA", new SHA384Digest(), new ECDSASigner());
+//        }
+//    }
+//    
+//    static public class ecDSA512
+//        extends JDKDSASigner
+//    {
+//        public ecDSA512()
+//        {
+//            super("SHA512withECDSA", new SHA512Digest(), new ECDSASigner());
+//        }
+//    }
+//    
+//
+//    static public class ecNR 
+//        extends JDKDSASigner
+//    {
+//        public ecNR()
+//        {
+//            super("SHA1withECNR", new SHA1Digest(), new ECNRSigner());
+//        }
+//    }
+//
+//    static public class ecNR224 
+//        extends JDKDSASigner
+//    {
+//        public ecNR224()
+//        {
+//            super("SHA224withECNR", new SHA224Digest(), new ECNRSigner());
+//        }
+//    }
+//
+//    static public class ecNR256 
+//        extends JDKDSASigner
+//    {
+//        public ecNR256()
+//        {
+//            super("SHA256withECNR", new SHA256Digest(), new ECNRSigner());
+//        }
+//    }
+//
+//    static public class ecNR384 
+//        extends JDKDSASigner
+//    {
+//        public ecNR384()
+//        {
+//            super("SHA384withECNR", new SHA384Digest(), new ECNRSigner());
+//        }
+//    }
+//
+//    static public class ecNR512 
+//        extends JDKDSASigner
+//    {
+//        public ecNR512()
+//        {
+//            super("SHA512withECNR", new SHA512Digest(), new ECNRSigner());
+//        }
+//    }
+// END android-removed
+    
+    private static class NullDigest
+        implements Digest
+    {
+        private ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+        
+        public String getAlgorithmName()
+        {
+            return "NULL";
+        }
+    
+        public int getDigestSize()
+        {
+            return bOut.size();
+        }
+    
+        public void update(byte in)
+        {
+            bOut.write(in);
+        }
+    
+        public void update(byte[] in, int inOff, int len)
+        {
+            bOut.write(in, inOff, len);
+        }
+    
+        public int doFinal(byte[] out, int outOff)
+        {
+            byte[] res = bOut.toByteArray();
+            
+            System.arraycopy(res, 0, out, outOff, res.length);
+            
+            return res.length;
+        }
+    
+        public void reset()
+        {
+            bOut.reset();
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKDigestSignature.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKDigestSignature.java
new file mode 100644
index 0000000..81a1027
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKDigestSignature.java
@@ -0,0 +1,339 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.DigestInfo;
+import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.MD2Digest;
+import org.bouncycastle.crypto.digests.MD4Digest;
+import org.bouncycastle.crypto.digests.MD5Digest;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.RIPEMD128Digest;
+// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
+// import org.bouncycastle.crypto.digests.RIPEMD256Digest;
+// END android-removed
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.digests.SHA224Digest;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.digests.SHA384Digest;
+import org.bouncycastle.crypto.digests.SHA512Digest;
+import org.bouncycastle.crypto.encodings.PKCS1Encoding;
+import org.bouncycastle.crypto.engines.RSAEngine;
+
+public class JDKDigestSignature
+    extends Signature implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+    private Digest                  digest;
+    private AsymmetricBlockCipher   cipher;
+    private AlgorithmIdentifier     algId;
+    
+    protected JDKDigestSignature(
+        String                  name,
+        DERObjectIdentifier     objId,
+        Digest                  digest,
+        AsymmetricBlockCipher   cipher)
+    {
+        super(name);
+
+        this.digest = digest;
+        this.cipher = cipher;
+        this.algId = new AlgorithmIdentifier(objId);
+    }
+
+    protected void engineInitVerify(
+        PublicKey   publicKey)
+        throws InvalidKeyException
+    {
+        if (!(publicKey instanceof RSAPublicKey))
+        {
+            throw new InvalidKeyException("Supplied key (" + getType(publicKey) + ") is not a RSAPublicKey instance");
+        }
+
+        CipherParameters    param = RSAUtil.generatePublicKeyParameter((RSAPublicKey)publicKey);
+
+        digest.reset();
+        cipher.init(false, param);
+    }
+
+    protected void engineInitSign(
+        PrivateKey  privateKey)
+        throws InvalidKeyException
+    {
+        if (!(privateKey instanceof RSAPrivateKey))
+        {
+            throw new InvalidKeyException("Supplied key (" + getType(privateKey) + ") is not a RSAPrivateKey instance");
+        }
+
+        CipherParameters    param = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey);
+
+        digest.reset();
+
+        cipher.init(true, param);
+    }
+
+    private String getType(
+        Object o)
+    {
+        if (o == null)
+        {
+            return null;
+        }
+        
+        return o.getClass().getName();
+    }
+    
+    protected void engineUpdate(
+        byte    b)
+        throws SignatureException
+    {
+        digest.update(b);
+    }
+
+    protected void engineUpdate(
+        byte[]  b,
+        int     off,
+        int     len) 
+        throws SignatureException
+    {
+        digest.update(b, off, len);
+    }
+
+    protected byte[] engineSign()
+        throws SignatureException
+    {
+        byte[]  hash = new byte[digest.getDigestSize()];
+
+        digest.doFinal(hash, 0);
+
+        try
+        {
+            byte[]  bytes = derEncode(hash);
+
+            return cipher.processBlock(bytes, 0, bytes.length);
+        }
+        catch (ArrayIndexOutOfBoundsException e)
+        {
+            throw new SignatureException("key too small for signature type");
+        }
+        catch (Exception e)
+        {
+            throw new SignatureException(e.toString());
+        }
+    }
+
+    protected boolean engineVerify(
+        byte[]  sigBytes) 
+        throws SignatureException
+    {
+        byte[]  hash = new byte[digest.getDigestSize()];
+
+        digest.doFinal(hash, 0);
+
+        byte[]      sig;
+        byte[]      expected;
+
+        try
+        {
+            sig = cipher.processBlock(sigBytes, 0, sigBytes.length);
+
+            expected = derEncode(hash);
+        }
+        catch (Exception e)
+        {
+            return false;
+        }
+
+        if (sig.length == expected.length)
+        {
+            for (int i = 0; i < sig.length; i++)
+            {
+                if (sig[i] != expected[i])
+                {
+                    return false;
+                }
+            }
+        }
+        else if (expected.length == sig.length - 2)  // NULL left out
+        {
+            int sigOffset = sig.length - hash.length - 2;
+            int expectedOffset = expected.length - hash.length - 2;
+
+            sig[1] -= 2;      // adjust lengths
+            sig[3] -= 2;
+
+            for (int i = 0; i < hash.length; i++)
+            {
+                if (sig[sigOffset + i] != expected[expectedOffset + i])  // check hash
+                {
+                    return false;
+                }
+            }
+
+            for (int i = 0; i < expectedOffset; i++)
+            {
+                if (sig[i] != expected[i])  // check header less NULL
+                {
+                    return false;
+                }
+            }
+        }
+        else
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    protected void engineSetParameter(
+        AlgorithmParameterSpec params)
+    {
+        throw new UnsupportedOperationException("engineSetParameter unsupported");
+    }
+
+    /**
+     * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+     */
+    protected void engineSetParameter(
+        String  param,
+        Object  value)
+    {
+        throw new UnsupportedOperationException("engineSetParameter unsupported");
+    }
+
+    /**
+     * @deprecated
+     */
+    protected Object engineGetParameter(
+        String      param)
+    {
+        throw new UnsupportedOperationException("engineSetParameter unsupported");
+    }
+
+    private byte[] derEncode(
+        byte[]  hash)
+        throws IOException
+    {
+        DigestInfo              dInfo = new DigestInfo(algId, hash);
+
+        return dInfo.getEncoded(ASN1Encodable.DER);
+    }
+
+    static public class SHA1WithRSAEncryption
+        extends JDKDigestSignature
+    {
+        public SHA1WithRSAEncryption()
+        {
+            super("SHA1withRSA", id_SHA1, new SHA1Digest(), new PKCS1Encoding(new RSAEngine()));
+        }
+    }
+
+    static public class SHA224WithRSAEncryption
+        extends JDKDigestSignature
+    {
+        public SHA224WithRSAEncryption()
+        {
+            super("SHA224withRSA", NISTObjectIdentifiers.id_sha224, new SHA224Digest(), new PKCS1Encoding(new RSAEngine()));
+        }
+    }
+
+    static public class SHA256WithRSAEncryption
+        extends JDKDigestSignature
+    {
+        public SHA256WithRSAEncryption()
+        {
+            super("SHA256withRSA", NISTObjectIdentifiers.id_sha256, new SHA256Digest(), new PKCS1Encoding(new RSAEngine()));
+        }
+    }
+    
+    static public class SHA384WithRSAEncryption
+        extends JDKDigestSignature
+    {
+        public SHA384WithRSAEncryption()
+        {
+            super("SHA384withRSA", NISTObjectIdentifiers.id_sha384, new SHA384Digest(), new PKCS1Encoding(new RSAEngine()));
+        }
+    }
+    
+    static public class SHA512WithRSAEncryption
+        extends JDKDigestSignature
+    {
+        public SHA512WithRSAEncryption()
+        {
+            super("SHA512withRSA", NISTObjectIdentifiers.id_sha512, new SHA512Digest(), new PKCS1Encoding(new RSAEngine()));
+        }
+    }
+    
+    static public class MD2WithRSAEncryption
+        extends JDKDigestSignature
+    {
+        public MD2WithRSAEncryption()
+        {
+            super("MD2withRSA", md2, new MD2Digest(), new PKCS1Encoding(new RSAEngine()));
+        }
+    }
+
+    static public class MD4WithRSAEncryption
+        extends JDKDigestSignature
+    {
+        public MD4WithRSAEncryption()
+        {
+            super("MD4withRSA", md4, new MD4Digest(), new PKCS1Encoding(new RSAEngine()));
+        }
+    }
+
+    static public class MD5WithRSAEncryption
+        extends JDKDigestSignature
+    {
+        public MD5WithRSAEncryption()
+        {
+            super("MD5withRSA", md5, new MD5Digest(), new PKCS1Encoding(new RSAEngine()));
+        }
+    }
+
+// BEGIN android-removed
+//    static public class RIPEMD160WithRSAEncryption
+//        extends JDKDigestSignature
+//    {
+//        public RIPEMD160WithRSAEncryption()
+//        {
+//            super("RIPEMD160withRSA", TeleTrusTObjectIdentifiers.ripemd160, new RIPEMD160Digest(), new PKCS1Encoding(new RSAEngine()));
+//        }
+//    }
+//    
+//    static public class RIPEMD128WithRSAEncryption
+//        extends JDKDigestSignature
+//    {
+//        public RIPEMD128WithRSAEncryption()
+//        {
+//            super("RIPEMD128withRSA", TeleTrusTObjectIdentifiers.ripemd128, new RIPEMD128Digest(), new PKCS1Encoding(new RSAEngine()));
+//        }
+//    }
+//    
+//    static public class RIPEMD256WithRSAEncryption
+//        extends JDKDigestSignature
+//    {
+//        public RIPEMD256WithRSAEncryption()
+//        {
+//            super("RIPEMD256withRSA", TeleTrusTObjectIdentifiers.ripemd256, new RIPEMD256Digest(), new PKCS1Encoding(new RSAEngine()));
+//        }
+//    }
+// END android-removed
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKECDSAAlgParameters.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKECDSAAlgParameters.java
new file mode 100644
index 0000000..557c705
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKECDSAAlgParameters.java
@@ -0,0 +1,75 @@
+package org.bouncycastle.jce.provider;
+
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DEROctetString;
+
+import java.io.IOException;
+import java.security.AlgorithmParametersSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+public abstract class JDKECDSAAlgParameters
+    extends AlgorithmParametersSpi
+{
+    public static class SigAlgParameters
+        extends JDKAlgorithmParameters
+    {
+        private DEREncodable  params;
+
+        protected byte[] engineGetEncoded() 
+            throws IOException
+        {
+            return engineGetEncoded("ASN.1");
+        }
+
+        protected byte[] engineGetEncoded(
+            String format) 
+            throws IOException
+        {
+            if (format == null)
+            {
+                return engineGetEncoded("ASN.1");
+            }
+            
+            if (format.equals("ASN.1"))
+            {
+                return new DEROctetString(engineGetEncoded("RAW")).getEncoded();
+            }
+
+            return null;
+        }
+
+        protected AlgorithmParameterSpec engineGetParameterSpec(
+            Class paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            throw new InvalidParameterSpecException("unknown parameter spec passed to ECDSA parameters object.");
+        }
+
+        protected void engineInit(
+            AlgorithmParameterSpec paramSpec) 
+            throws InvalidParameterSpecException
+        {
+            throw new InvalidParameterSpecException("unknown parameter spec passed to ECDSA parameters object.");
+        }
+
+        protected void engineInit(
+            byte[] params) 
+            throws IOException
+        {
+        }
+
+        protected void engineInit(
+            byte[] params,
+            String format) 
+            throws IOException
+        {
+            throw new IOException("Unknown parameters format in IV parameters object");
+        }
+
+        protected String engineToString() 
+        {
+            return "ECDSA Parameters";
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKISOSignature.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKISOSignature.java
new file mode 100644
index 0000000..ec8667d
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKISOSignature.java
@@ -0,0 +1,149 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.MD5Digest;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
+// END android-removed
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.engines.RSAEngine;
+import org.bouncycastle.crypto.signers.ISO9796d2Signer;
+
+public class JDKISOSignature
+    extends Signature
+{
+    private ISO9796d2Signer         signer;
+
+    protected JDKISOSignature(
+        String                  name,
+        Digest                  digest,
+        AsymmetricBlockCipher   cipher)
+    {
+        super(name);
+
+        signer = new ISO9796d2Signer(cipher, digest, true);
+    }
+
+    protected void engineInitVerify(
+        PublicKey   publicKey)
+        throws InvalidKeyException
+    {
+        CipherParameters    param = RSAUtil.generatePublicKeyParameter((RSAPublicKey)publicKey);
+
+        signer.init(false, param);
+    }
+
+    protected void engineInitSign(
+        PrivateKey  privateKey)
+        throws InvalidKeyException
+    {
+        CipherParameters    param = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey);
+
+        signer.init(true, param);
+    }
+
+    protected void engineUpdate(
+        byte    b)
+        throws SignatureException
+    {
+        signer.update(b);
+    }
+
+    protected void engineUpdate(
+        byte[]  b,
+        int     off,
+        int     len) 
+        throws SignatureException
+    {
+        signer.update(b, off, len);
+    }
+
+    protected byte[] engineSign()
+        throws SignatureException
+    {
+        try
+        {
+            byte[]  sig = signer.generateSignature();
+
+            return sig;
+        }
+        catch (Exception e)
+        {
+            throw new SignatureException(e.toString());
+        }
+    }
+
+    protected boolean engineVerify(
+        byte[]  sigBytes) 
+        throws SignatureException
+    {
+        boolean yes = signer.verifySignature(sigBytes);
+
+        return yes;
+    }
+
+    protected void engineSetParameter(
+        AlgorithmParameterSpec params)
+    {
+        throw new UnsupportedOperationException("engineSetParameter unsupported");
+    }
+
+    /**
+     * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+     */
+    protected void engineSetParameter(
+        String  param,
+        Object  value)
+    {
+        throw new UnsupportedOperationException("engineSetParameter unsupported");
+    }
+
+    /**
+     * @deprecated
+     */
+    protected Object engineGetParameter(
+        String      param)
+    {
+        throw new UnsupportedOperationException("engineSetParameter unsupported");
+    }
+
+    static public class SHA1WithRSAEncryption
+        extends JDKISOSignature
+    {
+        public SHA1WithRSAEncryption()
+        {
+            super("SHA1withRSA/ISO9796-2", new SHA1Digest(), new RSAEngine());
+        }
+    }
+
+    static public class MD5WithRSAEncryption
+        extends JDKISOSignature
+    {
+        public MD5WithRSAEncryption()
+        {
+            super("MD5withRSA/ISO9796-2", new MD5Digest(), new RSAEngine());
+        }
+    }
+
+// BEGIN android-removed
+//    static public class RIPEMD160WithRSAEncryption
+//        extends JDKISOSignature
+//    {
+//        public RIPEMD160WithRSAEncryption()
+//        {
+//            super("RIPEMD160withRSA/ISO9796-2", new RIPEMD160Digest(), new RSAEngine());
+//        }
+//    }
+// END android-removed
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKKeyFactory.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKKeyFactory.java
new file mode 100644
index 0000000..d5a05df
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKKeyFactory.java
@@ -0,0 +1,779 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.DSAPublicKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.DSAPrivateKeySpec;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPrivateKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHPrivateKeySpec;
+import javax.crypto.spec.DHPublicKeySpec;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+// BEGIN android-removed
+// import org.bouncycastle.jce.interfaces.ElGamalPrivateKey;
+// import org.bouncycastle.jce.interfaces.ElGamalPublicKey;
+// import org.bouncycastle.jce.spec.ECPrivateKeySpec;
+// import org.bouncycastle.jce.spec.ECPublicKeySpec;
+// import org.bouncycastle.jce.spec.ElGamalPrivateKeySpec;
+// import org.bouncycastle.jce.spec.ElGamalPublicKeySpec;
+// import org.bouncycastle.jce.spec.GOST3410PrivateKeySpec;
+// import org.bouncycastle.jce.spec.GOST3410PublicKeySpec;
+// END android-removed
+
+public abstract class JDKKeyFactory
+    extends KeyFactorySpi
+{
+    protected boolean elGamalFactory = false;
+    
+    public JDKKeyFactory()
+    {
+    }
+
+    protected KeySpec engineGetKeySpec(
+        Key    key,
+        Class    spec)
+    throws InvalidKeySpecException
+    {
+       if (spec.isAssignableFrom(PKCS8EncodedKeySpec.class) && key.getFormat().equals("PKCS#8"))
+       {
+               return new PKCS8EncodedKeySpec(key.getEncoded());
+       }
+       else if (spec.isAssignableFrom(X509EncodedKeySpec.class) && key.getFormat().equals("X.509"))
+       {
+               return new X509EncodedKeySpec(key.getEncoded());
+       }
+       else if (spec.isAssignableFrom(RSAPublicKeySpec.class) && key instanceof RSAPublicKey)
+       {
+            RSAPublicKey    k = (RSAPublicKey)key;
+
+            return new RSAPublicKeySpec(k.getModulus(), k.getPublicExponent());
+       }
+       else if (spec.isAssignableFrom(RSAPrivateKeySpec.class) && key instanceof RSAPrivateKey)
+       {
+            RSAPrivateKey    k = (RSAPrivateKey)key;
+
+            return new RSAPrivateKeySpec(k.getModulus(), k.getPrivateExponent());
+       }
+       else if (spec.isAssignableFrom(RSAPrivateCrtKeySpec.class) && key instanceof RSAPrivateCrtKey)
+       {
+            RSAPrivateCrtKey    k = (RSAPrivateCrtKey)key;
+
+            return new RSAPrivateCrtKeySpec(
+                            k.getModulus(), k.getPublicExponent(),
+                            k.getPrivateExponent(),
+                            k.getPrimeP(), k.getPrimeQ(),
+                            k.getPrimeExponentP(), k.getPrimeExponentQ(),
+                            k.getCrtCoefficient());
+       }
+       else if (spec.isAssignableFrom(DHPrivateKeySpec.class) && key instanceof DHPrivateKey)
+       {
+           DHPrivateKey k = (DHPrivateKey)key;
+           
+           return new DHPrivateKeySpec(k.getX(), k.getParams().getP(), k.getParams().getG());
+       }
+       else if (spec.isAssignableFrom(DHPublicKeySpec.class) && key instanceof DHPublicKey)
+       {
+           DHPublicKey k = (DHPublicKey)key;
+           
+           return new DHPublicKeySpec(k.getY(), k.getParams().getP(), k.getParams().getG());
+       }
+
+        throw new RuntimeException("not implemented yet " + key + " " + spec);
+    }
+
+    protected Key engineTranslateKey(
+        Key    key)
+        throws InvalidKeyException
+    {
+        if (key instanceof RSAPublicKey)
+        {
+            return new JCERSAPublicKey((RSAPublicKey)key);
+        }
+        else if (key instanceof RSAPrivateCrtKey)
+        {
+            return new JCERSAPrivateCrtKey((RSAPrivateCrtKey)key);
+        }
+        else if (key instanceof RSAPrivateKey)
+        {
+            return new JCERSAPrivateKey((RSAPrivateKey)key);
+        }
+        else if (key instanceof DHPublicKey)
+        {
+            // BEGIN android-removed
+            // if (elGamalFactory)
+            // {
+            //     return new JCEElGamalPublicKey((DHPublicKey)key);
+            // }
+            // else
+            // {
+            // END android-removed
+                return new JCEDHPublicKey((DHPublicKey)key);
+            // BEGIN android-removed
+            // }
+            // END android-removed
+        }
+        else if (key instanceof DHPrivateKey)
+        {
+            // BEGIN android-removed
+            // if (elGamalFactory)
+            // {
+            //     return new JCEElGamalPrivateKey((DHPrivateKey)key);
+            // }
+            // else
+            // {
+            // END android-removed
+                return new JCEDHPrivateKey((DHPrivateKey)key);
+            // BEGIN android-removed
+            // }
+            // END android-removed
+        }
+        else if (key instanceof DSAPublicKey)
+        {
+            return new JDKDSAPublicKey((DSAPublicKey)key);
+        }
+        else if (key instanceof DSAPrivateKey)
+        {
+            return new JDKDSAPrivateKey((DSAPrivateKey)key);
+        }
+        // BEGIN android-removed
+        // else if (key instanceof ElGamalPublicKey)
+        // {
+        //     return new JCEElGamalPublicKey((ElGamalPublicKey)key);
+        // }
+        // else if (key instanceof ElGamalPrivateKey)
+        // {
+        //    return new JCEElGamalPrivateKey((ElGamalPrivateKey)key);
+        // }
+        // END android-removed
+
+        throw new InvalidKeyException("key type unknown");
+    }
+
+    /**
+     * create a public key from the given DER encoded input stream. 
+     */ 
+    static PublicKey createPublicKeyFromDERStream(
+        byte[]         in)
+        throws IOException
+    {
+        return createPublicKeyFromPublicKeyInfo(
+                new SubjectPublicKeyInfo((ASN1Sequence)(new ASN1InputStream(in).readObject())));
+    }
+
+    /**
+     * create a public key from the given public key info object.
+     */ 
+    static PublicKey createPublicKeyFromPublicKeyInfo(
+        SubjectPublicKeyInfo         info)
+    {
+        DERObjectIdentifier     algOid = info.getAlgorithmId().getObjectId();
+        
+        if (RSAUtil.isRsaOid(algOid))
+        {
+            return new JCERSAPublicKey(info);
+        }
+        else if (algOid.equals(PKCSObjectIdentifiers.dhKeyAgreement))
+        {
+            return new JCEDHPublicKey(info);
+        }
+        else if (algOid.equals(X9ObjectIdentifiers.dhpublicnumber))
+        {
+            return new JCEDHPublicKey(info);
+        }
+        // BEGIN android-removed
+        // else if (algOid.equals(OIWObjectIdentifiers.elGamalAlgorithm))
+        // {
+        //     return new JCEElGamalPublicKey(info);
+        // }
+        // END android-removed
+        else if (algOid.equals(X9ObjectIdentifiers.id_dsa))
+        {
+            return new JDKDSAPublicKey(info);
+        }
+        else if (algOid.equals(OIWObjectIdentifiers.dsaWithSHA1))
+        {
+            return new JDKDSAPublicKey(info);
+        }
+        // BEGIN android-removed
+        // else if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
+        // {
+        //     return new JCEECPublicKey(info);
+        // }
+        // else if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_94))
+        // {
+        //     return new JDKGOST3410PublicKey(info);
+        // }
+        // else if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_2001))
+        // {
+        //     return new JCEECPublicKey(info);
+        // }
+        else
+        {
+            throw new RuntimeException("algorithm identifier " + algOid + " in key not recognised");
+        }
+    }
+
+    /**
+     * create a private key from the given DER encoded input stream. 
+     */ 
+    static PrivateKey createPrivateKeyFromDERStream(
+        byte[]         in)
+        throws IOException
+    {
+        return createPrivateKeyFromPrivateKeyInfo(
+                new PrivateKeyInfo((ASN1Sequence)(new ASN1InputStream(in).readObject())));
+    }
+
+    /**
+     * create a private key from the given public key info object.
+     */ 
+    static PrivateKey createPrivateKeyFromPrivateKeyInfo(
+        PrivateKeyInfo      info)
+    {
+        DERObjectIdentifier     algOid = info.getAlgorithmId().getObjectId();
+        
+        if (RSAUtil.isRsaOid(algOid))
+        {
+              return new JCERSAPrivateCrtKey(info);
+        }
+        else if (algOid.equals(PKCSObjectIdentifiers.dhKeyAgreement))
+        {
+              return new JCEDHPrivateKey(info);
+        }
+        // BEGIN android-removed
+        // else if (algOid.equals(OIWObjectIdentifiers.elGamalAlgorithm))
+        // {
+        //       return new JCEElGamalPrivateKey(info);
+        // }
+        // END android-removed
+        else if (algOid.equals(X9ObjectIdentifiers.id_dsa))
+        {
+              return new JDKDSAPrivateKey(info);
+        }
+        // BEGIN android-removed
+        // else if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
+        // {
+        //       return new JCEECPrivateKey(info);
+        // }
+        // else if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_94))
+        // {
+        //       return new JDKGOST3410PrivateKey(info);
+        // }
+        // else if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_2001))
+        // {
+        //       return new JCEECPrivateKey(info);
+        // }
+        // END android-removed
+        else
+        {
+            throw new RuntimeException("algorithm identifier " + algOid + " in key not recognised");
+        }
+    }
+
+    public static class RSA
+        extends JDKKeyFactory
+    {
+        public RSA()
+        {
+        }
+
+        protected PrivateKey engineGeneratePrivate(
+            KeySpec    keySpec)
+            throws InvalidKeySpecException
+        {
+            if (keySpec instanceof PKCS8EncodedKeySpec)
+            {
+                try
+                {
+                    return JDKKeyFactory.createPrivateKeyFromDERStream(
+                                ((PKCS8EncodedKeySpec)keySpec).getEncoded());
+                }
+                catch (Exception e)
+                {
+                    //
+                    // in case it's just a RSAPrivateKey object...
+                    //
+                    try
+                    {
+                        return new JCERSAPrivateCrtKey(
+                            new RSAPrivateKeyStructure(
+                                (ASN1Sequence)new ASN1InputStream(((PKCS8EncodedKeySpec)keySpec).getEncoded()).readObject()));
+                    }
+                    catch (Exception ex)
+                    {
+                        throw new InvalidKeySpecException(ex.toString());
+                    }
+                }
+            }
+            else if (keySpec instanceof RSAPrivateCrtKeySpec)
+            {
+                return new JCERSAPrivateCrtKey((RSAPrivateCrtKeySpec)keySpec);
+            }
+            else if (keySpec instanceof RSAPrivateKeySpec)
+            {
+                return new JCERSAPrivateKey((RSAPrivateKeySpec)keySpec);
+            }
+    
+            throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+        }
+    
+        protected PublicKey engineGeneratePublic(
+            KeySpec    keySpec)
+            throws InvalidKeySpecException
+        {
+            if (keySpec instanceof X509EncodedKeySpec)
+            {
+                try
+                {
+                    return JDKKeyFactory.createPublicKeyFromDERStream(
+                                ((X509EncodedKeySpec)keySpec).getEncoded());
+                }
+                catch (Exception e)
+                {
+                    throw new InvalidKeySpecException(e.toString());
+                }
+            }
+            else if (keySpec instanceof RSAPublicKeySpec)
+            {
+                return new JCERSAPublicKey((RSAPublicKeySpec)keySpec);
+            }
+    
+            throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+        }
+    }
+
+    public static class DH
+        extends JDKKeyFactory
+    {
+        public DH()
+        {
+        }
+
+        protected PrivateKey engineGeneratePrivate(
+            KeySpec    keySpec)
+            throws InvalidKeySpecException
+        {
+            if (keySpec instanceof PKCS8EncodedKeySpec)
+            {
+                try
+                {
+                    return JDKKeyFactory.createPrivateKeyFromDERStream(
+                                ((PKCS8EncodedKeySpec)keySpec).getEncoded());
+                }
+                catch (Exception e)
+                {
+                    throw new InvalidKeySpecException(e.toString());
+                }
+            }
+            else if (keySpec instanceof DHPrivateKeySpec)
+            {
+                return new JCEDHPrivateKey((DHPrivateKeySpec)keySpec);
+            }
+    
+            throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+        }
+    
+        protected PublicKey engineGeneratePublic(
+            KeySpec    keySpec)
+            throws InvalidKeySpecException
+        {
+            if (keySpec instanceof X509EncodedKeySpec)
+            {
+                try
+                {
+                    return JDKKeyFactory.createPublicKeyFromDERStream(
+                                ((X509EncodedKeySpec)keySpec).getEncoded());
+                }
+                catch (Exception e)
+                {
+                    throw new InvalidKeySpecException(e.toString());
+                }
+            }
+            else if (keySpec instanceof DHPublicKeySpec)
+            {
+                return new JCEDHPublicKey((DHPublicKeySpec)keySpec);
+            }
+    
+            throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+        }
+    }
+
+    public static class DSA
+        extends JDKKeyFactory
+    {
+        public DSA()
+        {
+        }
+
+        protected PrivateKey engineGeneratePrivate(
+            KeySpec    keySpec)
+            throws InvalidKeySpecException
+        {
+            if (keySpec instanceof PKCS8EncodedKeySpec)
+            {
+                try
+                {
+                    return JDKKeyFactory.createPrivateKeyFromDERStream(
+                                ((PKCS8EncodedKeySpec)keySpec).getEncoded());
+                }
+                catch (Exception e)
+                {
+                    throw new InvalidKeySpecException(e.toString());
+                }
+            }
+            else if (keySpec instanceof DSAPrivateKeySpec)
+            {
+                return new JDKDSAPrivateKey((DSAPrivateKeySpec)keySpec);
+            }
+    
+            throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+        }
+    
+        protected PublicKey engineGeneratePublic(
+            KeySpec    keySpec)
+            throws InvalidKeySpecException
+        {
+            if (keySpec instanceof X509EncodedKeySpec)
+            {
+                try
+                {
+                    return JDKKeyFactory.createPublicKeyFromDERStream(
+                                ((X509EncodedKeySpec)keySpec).getEncoded());
+                }
+                catch (Exception e)
+                {
+                    throw new InvalidKeySpecException(e.toString());
+                }
+            }
+            else if (keySpec instanceof DSAPublicKeySpec)
+            {
+                return new JDKDSAPublicKey((DSAPublicKeySpec)keySpec);
+            }
+    
+            throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+        }
+    }
+
+    public static class GOST3410
+        extends JDKKeyFactory
+    {
+        public GOST3410()
+        {
+        }
+        
+        protected PrivateKey engineGeneratePrivate(
+                KeySpec    keySpec)
+        throws InvalidKeySpecException
+        {
+            if (keySpec instanceof PKCS8EncodedKeySpec)
+            {
+                try
+                {
+                    return JDKKeyFactory.createPrivateKeyFromDERStream(
+                            ((PKCS8EncodedKeySpec)keySpec).getEncoded());
+                }
+                catch (Exception e)
+                {
+                    throw new InvalidKeySpecException(e.toString());
+                }
+            }
+            // BEGIN android-removed
+            // else if (keySpec instanceof GOST3410PrivateKeySpec)
+            // {
+            //     return new JDKGOST3410PrivateKey((GOST3410PrivateKeySpec)keySpec);
+            // }
+            // END android-removed
+            
+            throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+        }
+        
+        protected PublicKey engineGeneratePublic(
+                KeySpec    keySpec)
+        throws InvalidKeySpecException
+        {
+            if (keySpec instanceof X509EncodedKeySpec)
+            {
+                try
+                {
+                    return JDKKeyFactory.createPublicKeyFromDERStream(
+                            ((X509EncodedKeySpec)keySpec).getEncoded());
+                }
+                catch (Exception e)
+                {
+                    throw new InvalidKeySpecException(e.toString());
+                }
+            }
+            // BEGIN android-removed
+            // else if (keySpec instanceof GOST3410PublicKeySpec)
+            // {
+            //     return new JDKGOST3410PublicKey((GOST3410PublicKeySpec)keySpec);
+            // }
+            // END android-removed
+            
+            throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+        }
+    }
+    
+    public static class ElGamal
+        extends JDKKeyFactory
+    {
+        public ElGamal()
+        {
+            elGamalFactory = true;
+        }
+
+        protected PrivateKey engineGeneratePrivate(
+            KeySpec    keySpec)
+            throws InvalidKeySpecException
+        {
+            if (keySpec instanceof PKCS8EncodedKeySpec)
+            {
+                try
+                {
+                    return JDKKeyFactory.createPrivateKeyFromDERStream(
+                                ((PKCS8EncodedKeySpec)keySpec).getEncoded());
+                }
+                catch (Exception e)
+                {
+                    throw new InvalidKeySpecException(e.toString());
+                }
+            }
+            // BEGIN android-removed
+            // else if (keySpec instanceof ElGamalPrivateKeySpec)
+            // {
+            //     return new JCEElGamalPrivateKey((ElGamalPrivateKeySpec)keySpec);
+            // }
+            // else if (keySpec instanceof DHPrivateKeySpec)
+            // {
+            //     return new JCEElGamalPrivateKey((DHPrivateKeySpec)keySpec);
+            // }
+            // END android-removed
+    
+            throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+        }
+    
+        protected PublicKey engineGeneratePublic(
+            KeySpec    keySpec)
+            throws InvalidKeySpecException
+        {
+            if (keySpec instanceof X509EncodedKeySpec)
+            {
+                try
+                {
+                    return JDKKeyFactory.createPublicKeyFromDERStream(
+                                ((X509EncodedKeySpec)keySpec).getEncoded());
+                }
+                catch (Exception e)
+                {
+                    throw new InvalidKeySpecException(e.toString());
+                }
+            }
+            // BEGIN android-removed
+            // else if (keySpec instanceof ElGamalPublicKeySpec)
+            // {
+            //     return new JCEElGamalPublicKey((ElGamalPublicKeySpec)keySpec);
+            // }
+            // else if (keySpec instanceof DHPublicKeySpec)
+            // {
+            //     return new JCEElGamalPublicKey((DHPublicKeySpec)keySpec);
+            // }
+            // END android-removed
+    
+            throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+        }
+    }
+
+
+    /**
+     * This isn't really correct, however the class path project API seems to think such
+     * a key factory will exist.
+     */
+    public static class X509
+        extends JDKKeyFactory
+    {
+        public X509()
+        {
+        }
+    
+        protected PrivateKey engineGeneratePrivate(
+            KeySpec    keySpec)
+            throws InvalidKeySpecException
+        {
+            if (keySpec instanceof PKCS8EncodedKeySpec)
+            {
+                try
+                {
+                    return JDKKeyFactory.createPrivateKeyFromDERStream(
+                                ((PKCS8EncodedKeySpec)keySpec).getEncoded());
+                }
+                catch (Exception e)
+                {
+                    throw new InvalidKeySpecException(e.toString());
+                }
+            }
+    
+            throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+        }
+    
+        protected PublicKey engineGeneratePublic(
+            KeySpec    keySpec)
+            throws InvalidKeySpecException
+        {
+            if (keySpec instanceof X509EncodedKeySpec)
+            {
+                try
+                {
+                    return JDKKeyFactory.createPublicKeyFromDERStream(
+                                ((X509EncodedKeySpec)keySpec).getEncoded());
+                }
+                catch (Exception e)
+                {
+                    throw new InvalidKeySpecException(e.toString());
+                }
+            }
+    
+            throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+        }
+    }
+    
+    public static class EC
+        extends JDKKeyFactory
+    {
+        String  algorithm;
+
+        public EC()
+        {
+            this("EC");
+        }
+
+        public EC(
+            String  algorithm)
+        {
+            this.algorithm = algorithm;
+        }
+
+        protected PrivateKey engineGeneratePrivate(
+            KeySpec    keySpec)
+            throws InvalidKeySpecException
+        {
+            if (keySpec instanceof PKCS8EncodedKeySpec)
+            {
+                try
+                {
+                    return JDKKeyFactory.createPrivateKeyFromDERStream(
+                                ((PKCS8EncodedKeySpec)keySpec).getEncoded());
+                }
+                catch (Exception e)
+                {
+                    throw new InvalidKeySpecException(e.toString());
+                }
+            }
+            // BEGIN android-removed
+            // else if (keySpec instanceof ECPrivateKeySpec)
+            // {
+            //     return new JCEECPrivateKey(algorithm, (ECPrivateKeySpec)keySpec);
+            // }
+            // else if (keySpec instanceof java.security.spec.ECPrivateKeySpec)
+            // {
+            //     return new JCEECPrivateKey(algorithm, (java.security.spec.ECPrivateKeySpec)keySpec);
+            // }
+            // END android-removed
+    
+            throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+        }
+    
+        protected PublicKey engineGeneratePublic(
+            KeySpec    keySpec)
+            throws InvalidKeySpecException
+        {
+            if (keySpec instanceof X509EncodedKeySpec)
+            {
+                try
+                {
+                    return JDKKeyFactory.createPublicKeyFromDERStream(
+                                ((X509EncodedKeySpec)keySpec).getEncoded());
+                }
+                catch (Exception e)
+                {
+                    throw new InvalidKeySpecException(e.toString());
+                }
+            }
+            // BEGIN android-removed
+            // else if (keySpec instanceof ECPublicKeySpec)
+            // {
+            //     return new JCEECPublicKey(algorithm, (ECPublicKeySpec)keySpec);
+            // }
+            // else if (keySpec instanceof java.security.spec.ECPublicKeySpec)
+            // {
+            //     return new JCEECPublicKey(algorithm, (java.security.spec.ECPublicKeySpec)keySpec);
+            // }
+            // END android-removed
+    
+            throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+        }
+    }
+
+    public static class ECDSA
+        extends EC
+    {
+        public ECDSA()
+        {
+            super("ECDSA");
+        }
+    }
+
+    public static class ECGOST3410
+        extends EC
+    {
+        public ECGOST3410()
+        {
+            super("ECGOST3410");
+        }
+    }
+    
+    public static class ECDH
+        extends EC
+    {
+        public ECDH()
+        {
+            super("ECDH");
+        }
+    }
+
+    public static class ECDHC
+        extends EC
+    {
+        public ECDHC()
+        {
+            super("ECDHC");
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java
new file mode 100644
index 0000000..cb3b172
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java
@@ -0,0 +1,621 @@
+package org.bouncycastle.jce.provider;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.ECField;
+import java.security.spec.ECFieldF2m;
+import java.security.spec.ECFieldFp;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.RSAKeyGenParameterSpec;
+import java.util.Hashtable;
+
+import javax.crypto.spec.DHParameterSpec;
+
+import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+// import org.bouncycastle.asn1.nist.NISTNamedCurves;
+// import org.bouncycastle.asn1.sec.SECNamedCurves;
+// import org.bouncycastle.asn1.x9.X962NamedCurves;
+// import org.bouncycastle.asn1.x9.X9ECParameters;
+// END android-removed
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.generators.DHBasicKeyPairGenerator;
+import org.bouncycastle.crypto.generators.DHParametersGenerator;
+import org.bouncycastle.crypto.generators.DSAKeyPairGenerator;
+import org.bouncycastle.crypto.generators.DSAParametersGenerator;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
+// import org.bouncycastle.crypto.generators.ElGamalKeyPairGenerator;
+// import org.bouncycastle.crypto.generators.ElGamalParametersGenerator;
+// import org.bouncycastle.crypto.generators.GOST3410KeyPairGenerator;
+// END android-removed
+import org.bouncycastle.crypto.generators.RSAKeyPairGenerator;
+import org.bouncycastle.crypto.params.*;
+// BEGIN android-removed
+// import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
+// import org.bouncycastle.jce.spec.ECNamedCurveSpec;
+// import org.bouncycastle.jce.spec.ECParameterSpec;
+// import org.bouncycastle.jce.spec.ElGamalParameterSpec;
+// import org.bouncycastle.jce.spec.GOST3410ParameterSpec;
+// import org.bouncycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
+// import org.bouncycastle.math.ec.ECCurve;
+// import org.bouncycastle.math.ec.ECFieldElement;
+// import org.bouncycastle.math.ec.ECPoint;
+// END android-removed
+
+public abstract class JDKKeyPairGenerator
+    extends KeyPairGenerator
+{
+    public JDKKeyPairGenerator(
+        String              algorithmName)
+    {
+        super(algorithmName);
+    }
+
+    public abstract void initialize(int strength, SecureRandom random);
+
+    public abstract KeyPair generateKeyPair();
+
+    public static class RSA
+        extends JDKKeyPairGenerator
+    {
+        final static BigInteger defaultPublicExponent = BigInteger.valueOf(0x10001);
+        final static int defaultTests = 8;
+
+        RSAKeyGenerationParameters  param;
+        RSAKeyPairGenerator         engine;
+
+        public RSA()
+        {
+            super("RSA");
+
+            engine = new RSAKeyPairGenerator();
+            param = new RSAKeyGenerationParameters(defaultPublicExponent,
+                            new SecureRandom(), 2048, defaultTests);
+            engine.init(param);
+        }
+
+        public void initialize(
+            int             strength,
+            SecureRandom    random)
+        {
+            param = new RSAKeyGenerationParameters(defaultPublicExponent,
+                            random, strength, defaultTests);
+
+            engine.init(param);
+        }
+
+        public void initialize(
+            AlgorithmParameterSpec  params,
+            SecureRandom            random)
+            throws InvalidAlgorithmParameterException
+        {
+            if (!(params instanceof RSAKeyGenParameterSpec))
+            {
+                throw new InvalidAlgorithmParameterException("parameter object not a RSAKeyGenParameterSpec");
+            }
+            RSAKeyGenParameterSpec     rsaParams = (RSAKeyGenParameterSpec)params;
+
+            param = new RSAKeyGenerationParameters(
+                            rsaParams.getPublicExponent(),
+                            random, rsaParams.getKeysize(), defaultTests);
+
+            engine.init(param);
+        }
+
+        public KeyPair generateKeyPair()
+        {
+            AsymmetricCipherKeyPair     pair = engine.generateKeyPair();
+            RSAKeyParameters            pub = (RSAKeyParameters)pair.getPublic();
+            RSAPrivateCrtKeyParameters  priv = (RSAPrivateCrtKeyParameters)pair.getPrivate();
+
+            return new KeyPair(new JCERSAPublicKey(pub),
+                               new JCERSAPrivateCrtKey(priv));
+        }
+    }
+
+    public static class DH
+        extends JDKKeyPairGenerator
+    {
+        DHKeyGenerationParameters  param;
+        DHBasicKeyPairGenerator    engine = new DHBasicKeyPairGenerator();
+        int                        strength = 1024;
+        int                        certainty = 20;
+        SecureRandom               random = new SecureRandom();
+        boolean                    initialised = false;
+
+        public DH()
+        {
+            super("DH");
+        }
+
+        public void initialize(
+            int             strength,
+            SecureRandom    random)
+        {
+            this.strength = strength;
+            this.random = random;
+        }
+
+        public void initialize(
+            AlgorithmParameterSpec  params,
+            SecureRandom            random)
+            throws InvalidAlgorithmParameterException
+        {
+            if (!(params instanceof DHParameterSpec))
+            {
+                throw new InvalidAlgorithmParameterException("parameter object not a DHParameterSpec");
+            }
+            DHParameterSpec     dhParams = (DHParameterSpec)params;
+
+            param = new DHKeyGenerationParameters(random, new DHParameters(dhParams.getP(), dhParams.getG()));
+
+            engine.init(param);
+            initialised = true;
+        }
+
+        public KeyPair generateKeyPair()
+        {
+            if (!initialised)
+            {
+                DHParametersGenerator   pGen = new DHParametersGenerator();
+
+                pGen.init(strength, certainty, random);
+                param = new DHKeyGenerationParameters(random, pGen.generateParameters());
+                engine.init(param);
+                initialised = true;
+            }
+
+            AsymmetricCipherKeyPair   pair = engine.generateKeyPair();
+            DHPublicKeyParameters     pub = (DHPublicKeyParameters)pair.getPublic();
+            DHPrivateKeyParameters priv = (DHPrivateKeyParameters)pair.getPrivate();
+
+            return new KeyPair(new JCEDHPublicKey(pub),
+                               new JCEDHPrivateKey(priv));
+        }
+    }
+
+    public static class DSA
+        extends JDKKeyPairGenerator
+    {
+        DSAKeyGenerationParameters param;
+        DSAKeyPairGenerator        engine = new DSAKeyPairGenerator();
+        int                        strength = 1024;
+        int                        certainty = 20;
+        SecureRandom               random = new SecureRandom();
+        boolean                    initialised = false;
+
+        public DSA()
+        {
+            super("DSA");
+        }
+
+        public void initialize(
+            int             strength,
+            SecureRandom    random)
+        {
+            this.strength = strength;
+            this.random = random;
+        }
+
+        public void initialize(
+            AlgorithmParameterSpec  params,
+            SecureRandom            random)
+            throws InvalidAlgorithmParameterException
+        {
+            if (!(params instanceof DSAParameterSpec))
+            {
+                throw new InvalidAlgorithmParameterException("parameter object not a DSAParameterSpec");
+            }
+            DSAParameterSpec     dsaParams = (DSAParameterSpec)params;
+
+            param = new DSAKeyGenerationParameters(random, new DSAParameters(dsaParams.getP(), dsaParams.getQ(), dsaParams.getG()));
+
+            engine.init(param);
+            initialised = true;
+        }
+
+        public KeyPair generateKeyPair()
+        {
+            if (!initialised)
+            {
+                DSAParametersGenerator   pGen = new DSAParametersGenerator();
+
+                pGen.init(strength, certainty, random);
+                param = new DSAKeyGenerationParameters(random, pGen.generateParameters());
+                engine.init(param);
+                initialised = true;
+            }
+
+            AsymmetricCipherKeyPair   pair = engine.generateKeyPair();
+            DSAPublicKeyParameters     pub = (DSAPublicKeyParameters)pair.getPublic();
+            DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)pair.getPrivate();
+
+            return new KeyPair(new JDKDSAPublicKey(pub),
+                               new JDKDSAPrivateKey(priv));
+        }
+    }
+
+// BEGIN android-removed
+//    public static class ElGamal
+//        extends JDKKeyPairGenerator
+//    {
+//        ElGamalKeyGenerationParameters  param;
+//        ElGamalKeyPairGenerator         engine = new ElGamalKeyPairGenerator();
+//        int                             strength = 1024;
+//        int                             certainty = 20;
+//        SecureRandom                    random = new SecureRandom();
+//        boolean                         initialised = false;
+//
+//        public ElGamal()
+//        {
+//            super("ElGamal");
+//        }
+//
+//        public void initialize(
+//            int             strength,
+//            SecureRandom    random)
+//        {
+//            this.strength = strength;
+//            this.random = random;
+//        }
+//
+//        public void initialize(
+//            AlgorithmParameterSpec  params,
+//            SecureRandom            random)
+//            throws InvalidAlgorithmParameterException
+//        {
+//            if (!(params instanceof ElGamalParameterSpec) && !(params instanceof DHParameterSpec))
+//            {
+//                throw new InvalidAlgorithmParameterException("parameter object not a DHParameterSpec or an ElGamalParameterSpec");
+//            }
+//            
+//            if (params instanceof ElGamalParameterSpec)
+//            {
+//                ElGamalParameterSpec     elParams = (ElGamalParameterSpec)params;
+//
+//                param = new ElGamalKeyGenerationParameters(random, new ElGamalParameters(elParams.getP(), elParams.getG()));
+//            }
+//            else
+//            {
+//                DHParameterSpec     dhParams = (DHParameterSpec)params;
+//
+//                param = new ElGamalKeyGenerationParameters(random, new ElGamalParameters(dhParams.getP(), dhParams.getG()));
+//            }
+//
+//            engine.init(param);
+//            initialised = true;
+//        }
+//
+//        public KeyPair generateKeyPair()
+//        {
+//            if (!initialised)
+//            {
+//                ElGamalParametersGenerator   pGen = new ElGamalParametersGenerator();
+//
+//                pGen.init(strength, certainty, random);
+//                param = new ElGamalKeyGenerationParameters(random, pGen.generateParameters());
+//                engine.init(param);
+//                initialised = true;
+//            }
+//
+//            AsymmetricCipherKeyPair         pair = engine.generateKeyPair();
+//            ElGamalPublicKeyParameters      pub = (ElGamalPublicKeyParameters)pair.getPublic();
+//            ElGamalPrivateKeyParameters     priv = (ElGamalPrivateKeyParameters)pair.getPrivate();
+//
+//            return new KeyPair(new JCEElGamalPublicKey(pub),
+//                               new JCEElGamalPrivateKey(priv));
+//        }
+//    }
+//
+//    public static class GOST3410
+//        extends JDKKeyPairGenerator
+//    {
+//        GOST3410KeyGenerationParameters param;
+//        GOST3410KeyPairGenerator        engine = new GOST3410KeyPairGenerator();
+//        GOST3410ParameterSpec           gost3410Params;
+//        int                             strength = 1024;
+//        SecureRandom                    random = null;
+//        boolean                         initialised = false;
+//
+//        public GOST3410()
+//        {
+//            super("GOST3410");
+//        }
+//
+//        public void initialize(
+//            int             strength,
+//            SecureRandom    random)
+//        {
+//            this.strength = strength;
+//            this.random = random;
+//        }
+//    
+//        private void init(
+//            GOST3410ParameterSpec gParams,
+//            SecureRandom          random)
+//        {
+//            GOST3410PublicKeyParameterSetSpec spec = gParams.getPublicKeyParameters();
+//            
+//            param = new GOST3410KeyGenerationParameters(random, new GOST3410Parameters(spec.getP(), spec.getQ(), spec.getA()));
+//            
+//            engine.init(param);
+//            
+//            initialised = true;
+//            gost3410Params = gParams;
+//        }
+//        
+//        public void initialize(
+//            AlgorithmParameterSpec  params,
+//            SecureRandom            random)
+//            throws InvalidAlgorithmParameterException
+//        {
+//            if (!(params instanceof GOST3410ParameterSpec))
+//            {
+//                throw new InvalidAlgorithmParameterException("parameter object not a GOST3410ParameterSpec");
+//            }
+//            
+//            init((GOST3410ParameterSpec)params, random);
+//        }
+//
+//        public KeyPair generateKeyPair()
+//        {
+//            if (!initialised)
+//            {
+//                init(new GOST3410ParameterSpec(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_A.getId()), new SecureRandom());
+//            }
+//            
+//            AsymmetricCipherKeyPair   pair = engine.generateKeyPair();
+//            GOST3410PublicKeyParameters  pub = (GOST3410PublicKeyParameters)pair.getPublic();
+//            GOST3410PrivateKeyParameters priv = (GOST3410PrivateKeyParameters)pair.getPrivate();
+//            
+//            return new KeyPair(new JDKGOST3410PublicKey(pub, gost3410Params), new JDKGOST3410PrivateKey(priv, gost3410Params));
+//        }
+//   }
+//    
+//    public static class EC
+//        extends JDKKeyPairGenerator
+//    {
+//        ECKeyGenerationParameters   param;
+//        ECKeyPairGenerator          engine = new ECKeyPairGenerator();
+//        Object                      ecParams = null;
+//        int                         strength = 239;
+//        int                         certainty = 50;
+//        SecureRandom                random = new SecureRandom();
+//        boolean                     initialised = false;
+//        String                      algorithm;
+//
+//        static private Hashtable    ecParameters;
+//
+//        static {
+//            ecParameters = new Hashtable();
+//
+//            ecParameters.put(new Integer(192), new ECGenParameterSpec("prime192v1"));
+//            ecParameters.put(new Integer(239), new ECGenParameterSpec("prime239v1"));
+//            ecParameters.put(new Integer(256), new ECGenParameterSpec("prime256v1"));
+//        }
+//
+//        public EC()
+//        {
+//            super("EC");
+//            this.algorithm = "EC";
+//        }
+//        
+//        public EC(
+//            String  algorithm)
+//        {
+//            super(algorithm);
+//            this.algorithm = algorithm;
+//        }
+//
+//        public void initialize(
+//            int             strength,
+//            SecureRandom    random)
+//        {
+//            this.strength = strength;
+//            this.random = random;
+//            this.ecParams = (ECGenParameterSpec)ecParameters.get(new Integer(strength));
+//
+//            if (ecParams != null)
+//            {
+//                try
+//                {
+//                    initialize((ECGenParameterSpec)ecParams, random);
+//                }
+//                catch (InvalidAlgorithmParameterException e)
+//                {
+//                    throw new InvalidParameterException("key size not configurable.");
+//                }
+//            }
+//            else
+//            {
+//                throw new InvalidParameterException("unknown key size.");
+//            }
+//        }
+//
+//        public void initialize(
+//            AlgorithmParameterSpec  params,
+//            SecureRandom            random)
+//            throws InvalidAlgorithmParameterException
+//        {
+//            if (params instanceof ECParameterSpec)
+//            {
+//                ECParameterSpec p = (ECParameterSpec)params;
+//                this.ecParams = params;
+//    
+//                param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
+//    
+//                engine.init(param);
+//                initialised = true;
+//            }
+//            else if (params instanceof java.security.spec.ECParameterSpec)
+//            {
+//                java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)params;
+//                this.ecParams = params;
+//
+//                ECCurve curve;
+//                ECPoint g;
+//                ECField field = p.getCurve().getField();
+//
+//                if (field instanceof ECFieldFp)
+//                {
+//                    curve = new ECCurve.Fp(((ECFieldFp)p.getCurve().getField()).getP(), p.getCurve().getA(), p.getCurve().getB());
+//                    g = new ECPoint.Fp(curve, new ECFieldElement.Fp(((ECCurve.Fp)curve).getQ(), p.getGenerator().getAffineX()), new ECFieldElement.Fp(((ECCurve.Fp)curve).getQ(), p.getGenerator().getAffineY()));
+//                }
+//                else
+//                {
+//                    ECFieldF2m fieldF2m = (ECFieldF2m)field;
+//                    int m = fieldF2m.getM();
+//                    int ks[] = ECUtil.convertMidTerms(fieldF2m.getMidTermsOfReductionPolynomial());
+//                    curve = new ECCurve.F2m(m, ks[0], ks[1], ks[2], p.getCurve().getA(), p.getCurve().getB());
+//                    g = new ECPoint.F2m(curve, new ECFieldElement.F2m(m, ks[0], ks[1], ks[2], p.getGenerator().getAffineX()), new ECFieldElement.F2m(m, ks[0], ks[1], ks[2], p.getGenerator().getAffineY()), false);
+//                }
+//                param = new ECKeyGenerationParameters(new ECDomainParameters(curve, g, p.getOrder(), BigInteger.valueOf(p.getCofactor())), random);
+//    
+//                engine.init(param);
+//                initialised = true;
+//            }
+//            else if (params instanceof ECGenParameterSpec)
+//            {
+//                if (this.algorithm.equals("ECGOST3410"))
+//                {
+//                    ECDomainParameters  ecP = ECGOST3410NamedCurves.getByName(((ECGenParameterSpec)params).getName());
+//                    if (ecP == null)
+//                    {
+//                        throw new InvalidAlgorithmParameterException("unknown curve name: " + ((ECGenParameterSpec)params).getName());
+//                    }
+//
+//                    this.ecParams = new ECNamedCurveParameterSpec(
+//                                                    ((ECGenParameterSpec)params).getName(),
+//                                                    ecP.getCurve(),
+//                                                    ecP.getG(),
+//                                                    ecP.getN(),
+//                                                    ecP.getH(),
+//                                                    ecP.getSeed());
+//                }
+//                else
+//                {
+//                    X9ECParameters  ecP = X962NamedCurves.getByName(((ECGenParameterSpec)params).getName());
+//                    if (ecP == null)
+//                    {
+//                        ecP = SECNamedCurves.getByName(((ECGenParameterSpec)params).getName());
+//                        if (ecP == null)
+//                        {
+//                            ecP = NISTNamedCurves.getByName(((ECGenParameterSpec)params).getName());
+//                        }
+//                        if (ecP == null)
+//                        {
+//                            throw new InvalidAlgorithmParameterException("unknown curve name: " + ((ECGenParameterSpec)params).getName());
+//                        }
+//                    }
+//
+//                    this.ecParams = new ECNamedCurveSpec(
+//                            ((ECGenParameterSpec)params).getName(),
+//                            ecP.getCurve(),
+//                            ecP.getG(),
+//                            ecP.getN(),
+//                            ecP.getH(),
+//                            ecP.getSeed());
+//                }
+//
+//                java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)ecParams;
+//                ECCurve curve;
+//                ECPoint g;
+//                ECField field = p.getCurve().getField();
+//
+//                if (field instanceof ECFieldFp)
+//                {
+//                    curve = new ECCurve.Fp(((ECFieldFp)p.getCurve().getField()).getP(), p.getCurve().getA(), p.getCurve().getB());
+//                    g = new ECPoint.Fp(curve, new ECFieldElement.Fp(((ECCurve.Fp)curve).getQ(), p.getGenerator().getAffineX()), new ECFieldElement.Fp(((ECCurve.Fp)curve).getQ(), p.getGenerator().getAffineY()));
+//                }
+//                else
+//                {
+//                    ECFieldF2m fieldF2m = (ECFieldF2m)field;
+//                    int m = fieldF2m.getM();
+//                    int ks[] = ECUtil.convertMidTerms(fieldF2m.getMidTermsOfReductionPolynomial());
+//                    curve = new ECCurve.F2m(m, ks[0], ks[1], ks[2], p.getCurve().getA(), p.getCurve().getB());
+//                    g = new ECPoint.F2m(curve, new ECFieldElement.F2m(m, ks[0], ks[1], ks[2], p.getGenerator().getAffineX()), new ECFieldElement.F2m(m, ks[0], ks[1], ks[2], p.getGenerator().getAffineY()), false);
+//                }
+//
+//                param = new ECKeyGenerationParameters(new ECDomainParameters(curve, g, p.getOrder(), BigInteger.valueOf(p.getCofactor())), random);
+//
+//                engine.init(param);
+//                initialised = true;
+//            }
+//            else
+//            {
+//                throw new InvalidAlgorithmParameterException("parameter object not a ECParameterSpec");
+//            } 
+//        }
+//
+//        public KeyPair generateKeyPair()
+//        {
+//            if (!initialised)
+//            {
+//                throw new IllegalStateException("EC Key Pair Generator not initialised");
+//            }
+//
+//            AsymmetricCipherKeyPair     pair = engine.generateKeyPair();
+//            ECPublicKeyParameters       pub = (ECPublicKeyParameters)pair.getPublic();
+//            ECPrivateKeyParameters      priv = (ECPrivateKeyParameters)pair.getPrivate();
+//
+//            if (ecParams instanceof ECParameterSpec)
+//            {
+//                ECParameterSpec p = (ECParameterSpec)ecParams;
+//                
+//                return new KeyPair(new JCEECPublicKey(algorithm, pub, p),
+//                                   new JCEECPrivateKey(algorithm, priv, p));
+//            }
+//            else
+//            {
+//                java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)ecParams;
+//                
+//                return new KeyPair(new JCEECPublicKey(algorithm, pub, p), new JCEECPrivateKey(algorithm, priv, p));
+//            }
+//        }
+//    }
+//
+//    public static class ECDSA
+//        extends EC
+//    {
+//        public ECDSA()
+//        {
+//            super("ECDSA");
+//        }
+//    }
+//
+//    public static class ECGOST3410
+//        extends EC
+//    {
+//        public ECGOST3410()
+//        {
+//            super("ECGOST3410");
+//        }
+//    }
+//    
+//    public static class ECDH
+//        extends EC
+//    {
+//        public ECDH()
+//        {
+//            super("ECDH");
+//        }
+//    }
+//
+//    public static class ECDHC
+//        extends EC
+//    {
+//        public ECDHC()
+//        {
+//            super("ECDHC");
+//        }
+//    }
+// END android-removed
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKKeyStore.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKKeyStore.java
new file mode 100644
index 0000000..0b1002a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKKeyStore.java
@@ -0,0 +1,1068 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.*;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+// BEGIN android-added
+import org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigest;
+
+// END android-added
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.PBEParametersGenerator;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.SHA1Digest;
+// END android-removed
+import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;
+import org.bouncycastle.crypto.io.DigestInputStream;
+import org.bouncycastle.crypto.io.DigestOutputStream;
+import org.bouncycastle.crypto.io.MacInputStream;
+import org.bouncycastle.crypto.io.MacOutputStream;
+import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.jce.interfaces.BCKeyStore;
+
+public class JDKKeyStore
+    extends KeyStoreSpi
+    implements BCKeyStore
+{
+    private static final int    STORE_VERSION = 1;
+
+    private static final int    STORE_SALT_SIZE = 20;
+    private static final String STORE_CIPHER = "PBEWithSHAAndTwofish-CBC";
+
+    private static final int    KEY_SALT_SIZE = 20;
+    private static final int    MIN_ITERATIONS = 1024;
+
+    private static final String KEY_CIPHER = "PBEWithSHAAnd3-KeyTripleDES-CBC";
+
+    //
+    // generic object types
+    //
+    static final int NULL           = 0;
+    static final int CERTIFICATE    = 1;
+    static final int KEY            = 2;
+    static final int SECRET         = 3;
+    static final int SEALED         = 4;
+
+    //
+    // key types
+    //
+    static final int    KEY_PRIVATE = 0;
+    static final int    KEY_PUBLIC  = 1;
+    static final int    KEY_SECRET  = 2;
+
+    protected Hashtable       table = new Hashtable();
+
+    protected SecureRandom    random = new SecureRandom();
+
+    public JDKKeyStore()
+    {
+    }
+
+    private class StoreEntry
+    {
+        int             type;
+        String          alias;
+        Object          obj;
+        Certificate[]   certChain;
+        Date            date = new Date();
+
+        StoreEntry(
+            String       alias,
+            Certificate  obj)
+        {
+            this.type = CERTIFICATE;
+            this.alias = alias;
+            this.obj = obj;
+            this.certChain = null;
+        }
+
+        StoreEntry(
+            String          alias,
+            Key             obj,
+            Certificate[]   certChain)
+        {
+            this.type = KEY;
+            this.alias = alias;
+            this.obj = obj;
+            this.certChain = certChain;
+        }
+
+        StoreEntry(
+            String          alias,
+            byte[]          obj,
+            Certificate[]   certChain)
+        {
+            this.type = SECRET;
+            this.alias = alias;
+            this.obj = obj;
+            this.certChain = certChain;
+        }
+
+        StoreEntry(
+            String          alias,
+            Key             key,
+            char[]          password,
+            Certificate[]   certChain)
+            throws Exception
+        {
+            this.type = SEALED;
+            this.alias = alias;
+            this.certChain = certChain;
+
+            byte[] salt = new byte[KEY_SALT_SIZE];
+
+            random.setSeed(System.currentTimeMillis());
+            random.nextBytes(salt);
+
+            int iterationCount = MIN_ITERATIONS + (random.nextInt() & 0x3ff);
+
+
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DataOutputStream        dOut = new DataOutputStream(bOut);
+
+            dOut.writeInt(salt.length);
+            dOut.write(salt);
+            dOut.writeInt(iterationCount);
+
+            Cipher              cipher = makePBECipher(KEY_CIPHER, Cipher.ENCRYPT_MODE, password, salt, iterationCount);
+            CipherOutputStream  cOut = new CipherOutputStream(dOut, cipher);
+
+            dOut = new DataOutputStream(cOut);
+
+            encodeKey(key, dOut);
+
+            dOut.close();
+
+            obj = bOut.toByteArray();
+        }
+
+        StoreEntry(
+            String          alias,
+            Date            date,
+            int             type,
+            Object          obj)
+        {
+            this.alias = alias;
+            this.date = date;
+            this.type = type;
+            this.obj = obj;
+        }
+
+        StoreEntry(
+            String          alias,
+            Date            date,
+            int             type,
+            Object          obj,
+            Certificate[]   certChain)
+        {
+            this.alias = alias;
+            this.date = date;
+            this.type = type;
+            this.obj = obj;
+            this.certChain = certChain;
+        }
+
+        int getType()
+        {
+            return type;
+        }
+
+        String getAlias()
+        {
+            return alias;
+        }
+
+        Object getObject()
+        {
+            return obj;
+        }
+
+        Object getObject(
+            char[]  password)
+            throws NoSuchAlgorithmException, UnrecoverableKeyException
+        {
+            if (password == null || password.length == 0)
+            {
+                if (obj instanceof Key)
+                {
+                    return obj;
+                }
+            }
+
+            if (type == SEALED)
+            {
+                ByteArrayInputStream    bIn = new ByteArrayInputStream((byte[])obj);
+                DataInputStream         dIn = new DataInputStream(bIn);
+            
+                try
+                {
+                    byte[]      salt = new byte[dIn.readInt()];
+
+                    dIn.readFully(salt);
+
+                    int     iterationCount = dIn.readInt();
+                
+                    Cipher      cipher = makePBECipher(KEY_CIPHER, Cipher.DECRYPT_MODE, password, salt, iterationCount);
+
+                    CipherInputStream cIn = new CipherInputStream(dIn, cipher);
+
+                    try
+                    {
+                        return decodeKey(new DataInputStream(cIn));
+                    }
+                    catch (Exception x)
+                    {
+                        bIn = new ByteArrayInputStream((byte[])obj);
+                        dIn = new DataInputStream(bIn);
+            
+                        salt = new byte[dIn.readInt()];
+
+                        dIn.readFully(salt);
+
+                        iterationCount = dIn.readInt();
+
+                        cipher = makePBECipher("Broken" + KEY_CIPHER, Cipher.DECRYPT_MODE, password, salt, iterationCount);
+
+                        cIn = new CipherInputStream(dIn, cipher);
+
+                        Key k = null;
+
+                        try
+                        {
+                            k = decodeKey(new DataInputStream(cIn));
+                        }
+                        catch (Exception y)
+                        {
+                            bIn = new ByteArrayInputStream((byte[])obj);
+                            dIn = new DataInputStream(bIn);
+                
+                            salt = new byte[dIn.readInt()];
+
+                            dIn.readFully(salt);
+
+                            iterationCount = dIn.readInt();
+
+                            cipher = makePBECipher("Old" + KEY_CIPHER, Cipher.DECRYPT_MODE, password, salt, iterationCount);
+
+                            cIn = new CipherInputStream(dIn, cipher);
+
+                            k = decodeKey(new DataInputStream(cIn));
+                        }
+
+                        //
+                        // reencrypt key with correct cipher.
+                        //
+                        if (k != null)
+                        {
+                            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+                            DataOutputStream        dOut = new DataOutputStream(bOut);
+
+                            dOut.writeInt(salt.length);
+                            dOut.write(salt);
+                            dOut.writeInt(iterationCount);
+
+                            Cipher              out = makePBECipher(KEY_CIPHER, Cipher.ENCRYPT_MODE, password, salt, iterationCount);
+                            CipherOutputStream  cOut = new CipherOutputStream(dOut, out);
+
+                            dOut = new DataOutputStream(cOut);
+
+                            encodeKey(k, dOut);
+
+                            dOut.close();
+
+                            obj = bOut.toByteArray();
+
+                            return k;
+                        }
+                        else
+                        {
+                            throw new UnrecoverableKeyException("no match");
+                        }
+                    }
+                }
+                catch (Exception e)
+                {
+                    throw new UnrecoverableKeyException("no match");
+                }
+            }
+            else
+            {
+                throw new RuntimeException("forget something!");
+                // TODO
+                // if we get to here key was saved as byte data, which
+                // according to the docs means it must be a private key
+                // in EncryptedPrivateKeyInfo (PKCS8 format), later...
+                //
+            }
+        }
+
+        Certificate[] getCertificateChain()
+        {
+            return certChain;
+        }
+
+        Date getDate()
+        {
+            return date;
+        }
+    }
+
+    private void encodeCertificate(
+        Certificate         cert,
+        DataOutputStream    dOut)
+        throws IOException
+    {
+        try
+        {
+            byte[]      cEnc = cert.getEncoded();
+
+            dOut.writeUTF(cert.getType());
+            dOut.writeInt(cEnc.length);
+            dOut.write(cEnc);
+        }
+        catch (CertificateEncodingException ex)
+        {
+            throw new IOException(ex.toString());
+        }
+    }
+
+    private Certificate decodeCertificate(
+        DataInputStream   dIn)
+        throws IOException
+    {
+        String      type = dIn.readUTF();
+        byte[]      cEnc = new byte[dIn.readInt()];
+
+        dIn.readFully(cEnc);
+
+        try
+        {
+            CertificateFactory cFact = CertificateFactory.getInstance(type, "BC");
+            ByteArrayInputStream bIn = new ByteArrayInputStream(cEnc);
+
+            return cFact.generateCertificate(bIn);
+        }
+        catch (NoSuchProviderException ex)
+        {
+            throw new IOException(ex.toString());
+        }
+        catch (CertificateException ex)
+        {
+            throw new IOException(ex.toString());
+        }
+    }
+
+    private void encodeKey(
+        Key                 key,
+        DataOutputStream    dOut)
+        throws IOException
+    {
+        byte[]      enc = key.getEncoded();
+
+        if (key instanceof PrivateKey)
+        {
+            dOut.write(KEY_PRIVATE);
+        }
+        else if (key instanceof PublicKey)
+        {
+            dOut.write(KEY_PUBLIC);
+        }
+        else
+        {
+            dOut.write(KEY_SECRET);
+        }
+    
+        dOut.writeUTF(key.getFormat());
+        dOut.writeUTF(key.getAlgorithm());
+        dOut.writeInt(enc.length);
+        dOut.write(enc);
+    }
+
+    private Key decodeKey(
+        DataInputStream dIn)
+        throws IOException
+    {
+        int         keyType = dIn.read();
+        String      format = dIn.readUTF();
+        String      algorithm = dIn.readUTF();
+        byte[]      enc = new byte[dIn.readInt()];
+        KeySpec     spec;
+
+        dIn.readFully(enc);
+
+        if (format.equals("PKCS#8") || format.equals("PKCS8"))
+        {
+            spec = new PKCS8EncodedKeySpec(enc);
+        }
+        else if (format.equals("X.509") || format.equals("X509"))
+        {
+            spec = new X509EncodedKeySpec(enc);
+        }
+        else if (format.equals("RAW"))
+        {
+            return new SecretKeySpec(enc, algorithm);
+        }
+        else
+        {
+            throw new IOException("Key format " + format + " not recognised!");
+        }
+
+        try
+        {
+            switch (keyType)
+            {
+            case KEY_PRIVATE:
+                return KeyFactory.getInstance(algorithm, "BC").generatePrivate(spec);
+            case KEY_PUBLIC:
+                return KeyFactory.getInstance(algorithm, "BC").generatePublic(spec);
+            case KEY_SECRET:
+                return SecretKeyFactory.getInstance(algorithm, "BC").generateSecret(spec);
+            default:
+                throw new IOException("Key type " + keyType + " not recognised!");
+            }
+        }
+        catch (Exception e)
+        {
+            throw new IOException("Exception creating key: " + e.toString());
+        }
+    }
+
+    protected Cipher makePBECipher(
+        String  algorithm,
+        int     mode,
+        char[]  password,
+        byte[]  salt,
+        int     iterationCount)
+        throws IOException
+    {
+        try
+        {
+            PBEKeySpec          pbeSpec = new PBEKeySpec(password);
+            SecretKeyFactory    keyFact = SecretKeyFactory.getInstance(algorithm, "BC");
+            PBEParameterSpec    defParams = new PBEParameterSpec(salt, iterationCount);
+
+            Cipher cipher = Cipher.getInstance(algorithm, "BC");
+
+            cipher.init(mode, keyFact.generateSecret(pbeSpec), defParams);
+
+            return cipher;
+        }
+        catch (Exception e)
+        {
+            throw new IOException("Error initialising store of key store: " + e);
+        }
+    }
+
+    public void setRandom(
+            SecureRandom    rand)
+    {
+        this.random = rand;
+    }
+
+    public Enumeration engineAliases() 
+    {
+        return table.keys();
+    }
+
+    public boolean engineContainsAlias(
+        String  alias) 
+    {
+        return (table.get(alias) != null);
+    }
+
+    public void engineDeleteEntry(
+        String  alias) 
+        throws KeyStoreException
+    {
+        Object  entry = table.get(alias);
+
+        if (entry == null)
+        {
+            throw new KeyStoreException("no such entry as " + alias);
+        }
+
+        table.remove(alias);
+    }
+
+    public Certificate engineGetCertificate(
+        String alias) 
+    {
+        StoreEntry  entry = (StoreEntry)table.get(alias);
+
+        if (entry != null)
+        {
+            if (entry.getType() == CERTIFICATE)
+            {
+                return (Certificate)entry.getObject();
+            }
+            else
+            {
+                Certificate[]   chain = entry.getCertificateChain();
+
+                if (chain != null)
+                {
+                    return chain[0];
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public String engineGetCertificateAlias(
+        Certificate cert) 
+    {
+        Enumeration e = table.elements();
+        while (e.hasMoreElements())
+        {
+            StoreEntry  entry = (StoreEntry)e.nextElement();
+
+            if (entry.getObject() instanceof Certificate)
+            {
+                Certificate c = (Certificate)entry.getObject();
+
+                if (c.equals(cert))
+                {
+                    return entry.getAlias();
+                }
+            }
+            else
+            {
+                Certificate[]   chain = entry.getCertificateChain();
+
+                if (chain != null && chain[0].equals(cert))
+                {
+                    return entry.getAlias();
+                }
+            }
+        }
+
+        return null;
+    }
+    
+    public Certificate[] engineGetCertificateChain(
+        String alias) 
+    {
+        StoreEntry  entry = (StoreEntry)table.get(alias);
+
+        if (entry != null)
+        {
+            return entry.getCertificateChain();
+        }
+
+        return null;
+    }
+    
+    public Date engineGetCreationDate(String alias) 
+    {
+        StoreEntry  entry = (StoreEntry)table.get(alias);
+
+        if (entry != null)
+        {
+            return entry.getDate();
+        }
+
+        return null;
+    }
+
+    public Key engineGetKey(
+        String alias,
+        char[] password) 
+        throws NoSuchAlgorithmException, UnrecoverableKeyException
+    {
+        StoreEntry  entry = (StoreEntry)table.get(alias);
+
+        if (entry == null || entry.getType() == CERTIFICATE)
+        {
+            return null;
+        }
+
+        return (Key)entry.getObject(password);
+    }
+
+    public boolean engineIsCertificateEntry(
+        String alias) 
+    {
+        StoreEntry  entry = (StoreEntry)table.get(alias);
+
+        if (entry != null && entry.getType() == CERTIFICATE)
+        {
+            return true;
+        }
+    
+        return false;
+    }
+
+    public boolean engineIsKeyEntry(
+        String alias) 
+    {
+        StoreEntry  entry = (StoreEntry)table.get(alias);
+
+        if (entry != null && entry.getType() != CERTIFICATE)
+        {
+            return true;
+        }
+    
+        return false;
+    }
+
+    public void engineSetCertificateEntry(
+        String      alias,
+        Certificate cert) 
+        throws KeyStoreException
+    {
+        StoreEntry  entry = (StoreEntry)table.get(alias);
+
+        if (entry != null && entry.getType() != CERTIFICATE)
+        {
+            throw new KeyStoreException("key store already has an entry with alias " + alias);
+        }
+
+        table.put(alias, new StoreEntry(alias, cert));
+    }
+
+    public void engineSetKeyEntry(
+        String alias,
+        byte[] key,
+        Certificate[] chain) 
+        throws KeyStoreException
+    {
+        StoreEntry  entry = (StoreEntry)table.get(alias);
+
+        if (entry != null)
+        {
+            throw new KeyStoreException("key store already has an entry with alias " + alias);
+        }
+
+        table.put(alias, new StoreEntry(alias, key, chain));
+    }
+
+    public void engineSetKeyEntry(
+        String          alias,
+        Key             key,
+        char[]          password,
+        Certificate[]   chain) 
+        throws KeyStoreException
+    {
+        if ((key instanceof PrivateKey) && (chain == null))
+        {
+            throw new KeyStoreException("no certificate chain for private key");
+        }
+
+        StoreEntry  entry = (StoreEntry)table.get(alias);
+
+        if (entry != null && entry.getType() == CERTIFICATE)
+        {
+            throw new KeyStoreException("key store already has an entry with alias " + alias);
+        }
+
+        try
+        {
+            table.put(alias, new StoreEntry(alias, key, password, chain));
+        }
+        catch (Exception e)
+        {
+            throw new KeyStoreException(e.toString());
+        }
+    }
+
+    public int engineSize() 
+    {
+        return table.size();
+    }
+
+    protected boolean isSameAs(
+        byte[]  one,
+        byte[]  two)
+    {
+        if (one.length != two.length)
+        {
+            return false;
+        }
+
+        for (int i = 0; i != one.length; i++)
+        {
+            if (one[i] != two[i])
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    protected void loadStore(
+        InputStream in)
+        throws IOException
+    {
+        DataInputStream     dIn = new DataInputStream(in);
+        int                 type = dIn.read();
+
+        while (type > NULL)
+        {
+            String          alias = dIn.readUTF();
+            Date            date = new Date(dIn.readLong());
+            int             chainLength = dIn.readInt();
+            Certificate[]   chain = null;
+
+            if (chainLength != 0)
+            {
+                chain = new Certificate[chainLength];
+
+                for (int i = 0; i != chainLength; i++)
+                {
+                    chain[i] = decodeCertificate(dIn);
+                }
+            }
+
+            switch (type)
+            {
+            case CERTIFICATE:
+                    Certificate     cert = decodeCertificate(dIn);
+
+                    table.put(alias, new StoreEntry(alias, date, CERTIFICATE, cert));
+                    break;
+            case KEY:
+                    Key     key = decodeKey(dIn);
+                    table.put(alias, new StoreEntry(alias, date, KEY, key, chain));
+                    break;
+            case SECRET:
+            case SEALED:
+                    byte[]      b = new byte[dIn.readInt()];
+
+                    dIn.readFully(b);
+                    table.put(alias, new StoreEntry(alias, date, type, b, chain));
+                    break;
+            default:
+                    throw new RuntimeException("Unknown object type in store.");
+            }
+
+            type = dIn.read();
+        }
+    }
+
+    protected void saveStore(
+        OutputStream    out)
+        throws IOException
+    {
+        Enumeration         e = table.elements();
+        DataOutputStream    dOut = new DataOutputStream(out);
+
+        while (e.hasMoreElements())
+        {
+            StoreEntry  entry = (StoreEntry)e.nextElement();
+
+            dOut.write(entry.getType());
+            dOut.writeUTF(entry.getAlias());
+            dOut.writeLong(entry.getDate().getTime());
+
+            Certificate[]   chain = entry.getCertificateChain();
+            if (chain == null)
+            {
+                dOut.writeInt(0);
+            }
+            else
+            {
+                dOut.writeInt(chain.length);
+                for (int i = 0; i != chain.length; i++)
+                {
+                    encodeCertificate(chain[i], dOut);
+                }
+            }
+
+            switch (entry.getType())
+            {
+            case CERTIFICATE:
+                    encodeCertificate((Certificate)entry.getObject(), dOut);
+                    break;
+            case KEY:
+                    encodeKey((Key)entry.getObject(), dOut);
+                    break;
+            case SEALED:
+            case SECRET:
+                    byte[]  b = (byte[])entry.getObject();
+
+                    dOut.writeInt(b.length);
+                    dOut.write(b);
+                    break;
+            default:
+                    throw new RuntimeException("Unknown object type in store.");
+            }
+        }
+
+        dOut.write(NULL);
+    }
+
+    public void engineLoad(
+        InputStream stream,
+        char[]      password) 
+        throws IOException
+    {
+        table.clear();
+
+        if (stream == null)     // just initialising
+        {
+            return;
+        }
+
+        DataInputStream     dIn = new DataInputStream(stream);
+        int                 version = dIn.readInt();
+
+        if (version != STORE_VERSION)
+        {
+            if (version != 0)
+            {
+                throw new IOException("Wrong version of key store.");
+            }
+        }
+
+        byte[]      salt = new byte[dIn.readInt()];
+
+        dIn.readFully(salt);
+
+        int         iterationCount = dIn.readInt();
+
+// BEGIN android-removed
+//         HMac                    hMac = new HMac(new SHA1Digest());
+//         MacInputStream          mIn = new MacInputStream(dIn, hMac);
+//         PBEParametersGenerator  pbeGen = new PKCS12ParametersGenerator(new SHA1Digest());
+// END android-removed
+// BEGIN android-added
+        HMac                    hMac = new HMac(OpenSSLMessageDigest.getInstance("SHA-1"));        
+        MacInputStream          mIn = new MacInputStream(dIn, hMac);
+        PBEParametersGenerator  pbeGen = new PKCS12ParametersGenerator(OpenSSLMessageDigest.getInstance("SHA-1"));
+// END android-added
+        byte[]                  passKey = PBEParametersGenerator.PKCS12PasswordToBytes(password);
+
+        pbeGen.init(passKey, salt, iterationCount);
+
+        hMac.init(pbeGen.generateDerivedMacParameters(hMac.getMacSize()));
+
+        for (int i = 0; i != passKey.length; i++)
+        {
+            passKey[i] = 0;
+        }
+
+        loadStore(mIn);
+
+        byte[]  mac = new byte[hMac.getMacSize()];
+        byte[]  oldMac = new byte[hMac.getMacSize()];
+
+        hMac.doFinal(mac, 0);
+
+        for (int i = 0; i != oldMac.length; i++)
+        {
+            oldMac[i] = (byte)dIn.read();
+        }
+
+        //
+        // we only do an integrity check if the password is provided.
+        //
+        if ((password != null && password.length != 0) && !isSameAs(mac, oldMac))
+        {
+            table.clear();
+            throw new IOException("KeyStore integrity check failed.");
+        }
+    }
+
+
+    public void engineStore(OutputStream stream, char[] password) 
+        throws IOException
+    {
+        DataOutputStream    dOut = new DataOutputStream(stream);
+        byte[]              salt = new byte[STORE_SALT_SIZE];
+        int                 iterationCount = MIN_ITERATIONS + (random.nextInt() & 0x3ff);
+
+        random.nextBytes(salt);
+
+        dOut.writeInt(STORE_VERSION);
+        dOut.writeInt(salt.length);
+        dOut.write(salt);
+        dOut.writeInt(iterationCount);
+
+// BEGIN android-removed
+//        HMac                    hMac = new HMac(new SHA1Digest());
+//        MacOutputStream         mOut = new MacOutputStream(dOut, hMac);
+//        PBEParametersGenerator  pbeGen = new PKCS12ParametersGenerator(new SHA1Digest());
+// END android-removed
+// BEGIN android-added
+        HMac                    hMac = new HMac(OpenSSLMessageDigest.getInstance("SHA-1"));
+        MacOutputStream         mOut = new MacOutputStream(dOut, hMac);
+        PBEParametersGenerator  pbeGen = new PKCS12ParametersGenerator(OpenSSLMessageDigest.getInstance("SHA-1"));
+// END android-added
+        byte[]                  passKey = PBEParametersGenerator.PKCS12PasswordToBytes(password);
+
+        pbeGen.init(passKey, salt, iterationCount);
+
+        hMac.init(pbeGen.generateDerivedMacParameters(hMac.getMacSize()));
+
+        for (int i = 0; i != passKey.length; i++)
+        {
+            passKey[i] = 0;
+        }
+
+        saveStore(mOut);
+
+        byte[]  mac = new byte[hMac.getMacSize()];
+
+        hMac.doFinal(mac, 0);
+
+        dOut.write(mac);
+
+        dOut.close();
+    }
+
+    /**
+     * the BouncyCastle store. This wont work with the key tool as the
+     * store is stored encrypteed on disk, so the password is mandatory,
+     * however if you hard drive is in a bad part of town and you absolutely,
+     * positively, don't want nobody peeking at your things, this is the
+     * one to use, no problem! After all in a Bouncy Castle nothing can
+     * touch you.
+     *
+     * Also referred to by the alias UBER.
+     */
+    public static class BouncyCastleStore
+        extends JDKKeyStore
+    {
+        public void engineLoad(
+            InputStream stream,
+            char[]      password) 
+            throws IOException
+        {
+            table.clear();
+    
+            if (stream == null)     // just initialising
+            {
+                return;
+            }
+    
+            Cipher              cipher;
+            DataInputStream     dIn = new DataInputStream(stream);
+            int                 version = dIn.readInt();
+    
+            if (version != STORE_VERSION)
+            {
+                if (version != 0)
+                {
+                    throw new IOException("Wrong version of key store.");
+                }
+            }
+    
+            byte[]      salt = new byte[dIn.readInt()];
+
+            if (salt.length != STORE_SALT_SIZE)
+            {
+                throw new IOException("Key store corrupted.");
+            }
+    
+            dIn.readFully(salt);
+    
+            int         iterationCount = dIn.readInt();
+    
+            if ((iterationCount < 0) || (iterationCount > 4 *  MIN_ITERATIONS))
+            {
+                throw new IOException("Key store corrupted.");
+            }
+    
+            if (version == 0)
+            {
+                cipher = this.makePBECipher("Old" + STORE_CIPHER, Cipher.DECRYPT_MODE, password, salt, iterationCount);
+            }
+            else
+            {
+                cipher = this.makePBECipher(STORE_CIPHER, Cipher.DECRYPT_MODE, password, salt, iterationCount);
+            }
+    
+            CipherInputStream  cIn = new CipherInputStream(dIn, cipher);
+
+// BEGIN android-removed
+//            DigestInputStream  dgIn = new DigestInputStream(cIn, new SHA1Digest());
+// END android-removed
+// BEGIN android-added
+            DigestInputStream  dgIn = new DigestInputStream(cIn, OpenSSLMessageDigest.getInstance("SHA-1"));
+// END android-added
+            
+            this.loadStore(dgIn);
+    
+            Digest  dig = dgIn.getDigest();
+            int     digSize = dig.getDigestSize();
+            byte[]  hash = new byte[digSize];
+            byte[]  oldHash = new byte[digSize];
+    
+            dig.doFinal(hash, 0);
+    
+            for (int i = 0; i != digSize; i++)
+            {
+                oldHash[i] = (byte)cIn.read();
+            }
+    
+            if (!this.isSameAs(hash, oldHash))
+            {
+                table.clear();
+                throw new IOException("KeyStore integrity check failed.");
+            }
+        }
+    
+    
+        public void engineStore(OutputStream stream, char[] password) 
+            throws IOException
+        {
+            Cipher              cipher;
+            DataOutputStream    dOut = new DataOutputStream(stream);
+            byte[]              salt = new byte[STORE_SALT_SIZE];
+            int                 iterationCount = MIN_ITERATIONS + (random.nextInt() & 0x3ff);
+    
+            random.nextBytes(salt);
+    
+            dOut.writeInt(STORE_VERSION);
+            dOut.writeInt(salt.length);
+            dOut.write(salt);
+            dOut.writeInt(iterationCount);
+    
+            cipher = this.makePBECipher(STORE_CIPHER, Cipher.ENCRYPT_MODE, password, salt, iterationCount);
+    
+            CipherOutputStream  cOut = new CipherOutputStream(dOut, cipher);
+// BEGIN android-removed            
+//            DigestOutputStream  dgOut = new DigestOutputStream(cOut, new SHA1Digest());
+// END android-removed    
+// BEGIN android-added            
+            DigestOutputStream  dgOut = new DigestOutputStream(cOut, OpenSSLMessageDigest.getInstance("SHA-1"));
+//END android-added   
+            this.saveStore(dgOut);
+    
+            Digest  dig = dgOut.getDigest();
+            byte[]  hash = new byte[dig.getDigestSize()];
+    
+            dig.doFinal(hash, 0);
+    
+            cOut.write(hash);
+    
+            cOut.close();
+        }
+    }    
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKMessageDigest.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKMessageDigest.java
new file mode 100644
index 0000000..bc8f7dd
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKMessageDigest.java
@@ -0,0 +1,340 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.MessageDigest;
+
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.*;
+
+public class JDKMessageDigest
+    extends MessageDigest
+{
+    Digest  digest;
+
+    protected JDKMessageDigest(
+        Digest  digest)
+    {
+        super(digest.getAlgorithmName());
+
+        this.digest = digest;
+    }
+
+    public void engineReset() 
+    {
+        digest.reset();
+    }
+
+    public void engineUpdate(
+        byte    input) 
+    {
+        digest.update(input);
+    }
+
+    public void engineUpdate(
+        byte[]  input,
+        int     offset,
+        int     len) 
+    {
+        digest.update(input, offset, len);
+    }
+
+    public byte[] engineDigest() 
+    {
+        byte[]  digestBytes = new byte[digest.getDigestSize()];
+
+        digest.doFinal(digestBytes, 0);
+
+        return digestBytes;
+    }
+
+    /**
+     * classes that extend directly off us.
+     */
+    static public class SHA1
+        extends JDKMessageDigest
+        implements Cloneable
+    {
+        public SHA1()
+        {
+            super(new SHA1Digest());
+        }
+
+        public Object clone()
+            throws CloneNotSupportedException
+        {
+            SHA1 d = (SHA1)super.clone();
+            d.digest = new SHA1Digest((SHA1Digest)digest);
+
+            return d;
+        }
+    }
+
+    static public class SHA224
+        extends JDKMessageDigest
+        implements Cloneable
+    {
+        public SHA224()
+        {
+            super(new SHA224Digest());
+        }
+
+        public Object clone()
+            throws CloneNotSupportedException
+        {
+            SHA224 d = (SHA224)super.clone();
+            d.digest = new SHA224Digest((SHA224Digest)digest);
+
+            return d;
+        }
+    }
+
+    static public class SHA256
+        extends JDKMessageDigest
+        implements Cloneable
+    {
+        public SHA256()
+        {
+            super(new SHA256Digest());
+        }
+
+        public Object clone()
+            throws CloneNotSupportedException
+        {
+            SHA256 d = (SHA256)super.clone();
+            d.digest = new SHA256Digest((SHA256Digest)digest);
+
+            return d;
+        }
+    }
+
+    static public class SHA384
+        extends JDKMessageDigest
+        implements Cloneable
+    {
+        public SHA384()
+        {
+            super(new SHA384Digest());
+        }
+
+        public Object clone()
+            throws CloneNotSupportedException
+        {
+            SHA384 d = (SHA384)super.clone();
+            d.digest = new SHA384Digest((SHA384Digest)digest);
+
+            return d;
+        }
+    }
+
+    static public class SHA512
+        extends JDKMessageDigest
+        implements Cloneable
+    {
+        public SHA512()
+        {
+            super(new SHA512Digest());
+        }
+
+        public Object clone()
+            throws CloneNotSupportedException
+        {
+            SHA512 d = (SHA512)super.clone();
+            d.digest = new SHA512Digest((SHA512Digest)digest);
+
+            return d;
+        }
+    }
+
+// BEGIN android-removed
+//    static public class MD2
+//        extends JDKMessageDigest
+//        implements Cloneable
+//    {
+//        public MD2()
+//        {
+//            super(new MD2Digest());
+//        }
+//
+//        public Object clone()
+//            throws CloneNotSupportedException
+//        {
+//            MD2 d = (MD2)super.clone();
+//            d.digest = new MD2Digest((MD2Digest)digest);
+//
+//            return d;
+//        }
+//    }
+//
+//    static public class MD4
+//        extends JDKMessageDigest
+//        implements Cloneable
+//    {
+//        public MD4()
+//        {
+//            super(new MD4Digest());
+//        }
+//
+//        public Object clone()
+//            throws CloneNotSupportedException
+//        {
+//            MD4 d = (MD4)super.clone();
+//            d.digest = new MD4Digest((MD4Digest)digest);
+//
+//            return d;
+//        }
+//    }
+// END android-removed
+
+    static public class MD5
+        extends JDKMessageDigest
+        implements Cloneable
+    {
+        public MD5()
+        {
+            super(new MD5Digest());
+        }
+
+        public Object clone()
+            throws CloneNotSupportedException
+        {
+            MD5 d = (MD5)super.clone();
+            d.digest = new MD5Digest((MD5Digest)digest);
+
+            return d;
+        }
+    }
+
+// BEGIN android-removed
+//    static public class RIPEMD128
+//        extends JDKMessageDigest
+//        implements Cloneable
+//    {
+//        public RIPEMD128()
+//        {
+//            super(new RIPEMD128Digest());
+//        }
+//
+//        public Object clone()
+//            throws CloneNotSupportedException
+//        {
+//            RIPEMD128 d = (RIPEMD128)super.clone();
+//            d.digest = new RIPEMD128Digest((RIPEMD128Digest)digest);
+//
+//            return d;
+//        }
+//    }
+//
+//    static public class RIPEMD160
+//        extends JDKMessageDigest
+//        implements Cloneable
+//    {
+//        public RIPEMD160()
+//        {
+//            super(new RIPEMD160Digest());
+//        }
+//
+//        public Object clone()
+//            throws CloneNotSupportedException
+//        {
+//            RIPEMD160 d = (RIPEMD160)super.clone();
+//            d.digest = new RIPEMD160Digest((RIPEMD160Digest)digest);
+//
+//            return d;
+//        }
+//    }
+//    
+//    static public class RIPEMD256
+//        extends JDKMessageDigest
+//        implements Cloneable
+//    {
+//        public RIPEMD256()
+//        {
+//            super(new RIPEMD256Digest());
+//        }
+//
+//        public Object clone()
+//            throws CloneNotSupportedException
+//        {
+//            RIPEMD256 d = (RIPEMD256)super.clone();
+//            d.digest = new RIPEMD256Digest((RIPEMD256Digest)digest);
+//
+//            return d;
+//        }
+//    }
+//    
+//    static public class RIPEMD320
+//        extends JDKMessageDigest
+//        implements Cloneable
+//    {
+//        public RIPEMD320()
+//        {
+//            super(new RIPEMD320Digest());
+//        }
+//
+//        public Object clone()
+//            throws CloneNotSupportedException
+//        {
+//            RIPEMD320 d = (RIPEMD320)super.clone();
+//            d.digest = new RIPEMD320Digest((RIPEMD320Digest)digest);
+//
+//            return d;
+//        }
+//    }
+//    
+//    static public class Tiger
+//        extends JDKMessageDigest
+//        implements Cloneable
+//    {
+//        public Tiger()
+//        {
+//            super(new TigerDigest());
+//        }
+//
+//        public Object clone()
+//            throws CloneNotSupportedException
+//        {
+//            Tiger d = (Tiger)super.clone();
+//            d.digest = new TigerDigest((TigerDigest)digest);
+//
+//            return d;
+//        }
+//    }
+//    
+//    static public class GOST3411
+//        extends JDKMessageDigest
+//        implements Cloneable
+//    {
+//        public GOST3411()
+//        {
+//            super(new GOST3411Digest());
+//        }
+//    
+//        public Object clone()
+//        throws CloneNotSupportedException
+//        {
+//            GOST3411 d = (GOST3411)super.clone();
+//            d.digest = new GOST3411Digest((GOST3411Digest)digest);
+//
+//            return d;
+//        }
+//    }
+//    
+//    static public class Whirlpool
+//       extends JDKMessageDigest
+//       implements Cloneable
+//    {
+//        public Whirlpool()
+//        {
+//            super(new WhirlpoolDigest());
+//        }
+//        
+//        public Object clone()
+//        throws CloneNotSupportedException
+//        {
+//            Whirlpool d = (Whirlpool)super.clone();
+//            d.digest = new WhirlpoolDigest((WhirlpoolDigest)digest);
+//            
+//            return d;
+//        }
+//    }
+// END android-removed
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java
new file mode 100644
index 0000000..7846530
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java
@@ -0,0 +1,1515 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.Key;
+import java.security.KeyStoreException;
+import java.security.KeyStoreSpi;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.BERConstructedOctetString;
+import org.bouncycastle.asn1.BEROutputStream;
+import org.bouncycastle.asn1.DERBMPString;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERSet;
+import org.bouncycastle.asn1.pkcs.AuthenticatedSafe;
+import org.bouncycastle.asn1.pkcs.CertBag;
+import org.bouncycastle.asn1.pkcs.ContentInfo;
+import org.bouncycastle.asn1.pkcs.EncryptedData;
+import org.bouncycastle.asn1.pkcs.MacData;
+import org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.Pfx;
+import org.bouncycastle.asn1.pkcs.SafeBag;
+import org.bouncycastle.asn1.util.ASN1Dump;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.bouncycastle.asn1.x509.DigestInfo;
+import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x509.X509Extensions;
+import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import org.bouncycastle.jce.interfaces.BCKeyStore;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.bouncycastle.util.encoders.Hex;
+
+public class JDKPKCS12KeyStore
+    extends KeyStoreSpi
+    implements PKCSObjectIdentifiers, X509ObjectIdentifiers, BCKeyStore
+{
+    private static final int    SALT_SIZE = 20;
+    private static final int    MIN_ITERATIONS = 100;
+    
+    //
+    // SHA-1 and 3-key-triple DES.
+    //
+    private static final String KEY_ALGORITHM = "1.2.840.113549.1.12.1.3";
+
+    //
+    // SHA-1 and 40 bit RC2.
+    //
+    private static final String CERT_ALGORITHM = "1.2.840.113549.1.12.1.6";
+
+    private Hashtable                       keys = new Hashtable();
+    private Hashtable                       localIds = new Hashtable();
+    private Hashtable                       certs = new Hashtable();
+    private Hashtable                       chainCerts = new Hashtable();
+    private Hashtable                       keyCerts = new Hashtable();
+
+    //
+    // generic object types
+    //
+    static final int NULL           = 0;
+    static final int CERTIFICATE    = 1;
+    static final int KEY            = 2;
+    static final int SECRET         = 3;
+    static final int SEALED         = 4;
+
+    //
+    // key types
+    //
+    static final int    KEY_PRIVATE = 0;
+    static final int    KEY_PUBLIC  = 1;
+    static final int    KEY_SECRET  = 2;
+
+    protected SecureRandom      random = new SecureRandom();
+
+    private CertificateFactory  certFact = null;
+
+    private class CertId
+    {
+        byte[]  id;
+
+        CertId(
+            PublicKey  key)
+        {
+            this.id = createSubjectKeyId(key).getKeyIdentifier();
+        }
+
+        CertId(
+            byte[]  id)
+        {
+            this.id = id;
+        }
+
+        public int hashCode()
+        {
+            int hash = id[0] & 0xff;
+
+            for (int i = 1; i != id.length - 4; i++)
+            {
+                hash ^= ((id[i] & 0xff) << 24) | ((id[i + 1] & 0xff) << 16)
+                          | ((id[i + 2] & 0xff) << 8) | (id[i + 3] & 0xff);
+            }
+
+            return hash;
+        }
+
+        public boolean equals(
+            Object  o)
+        {
+            if (!(o instanceof CertId))
+            {
+                return false;
+            }
+
+            CertId  cId = (CertId)o;
+
+            if (cId.id.length != id.length)
+            {
+                return false;
+            }
+
+            for (int i = 0; i != id.length; i++)
+            {
+                if (cId.id[i] != id[i])
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+    }
+
+    public JDKPKCS12KeyStore(
+        String provider)
+    {
+        try
+        {
+            if (provider != null)
+            {
+                certFact = CertificateFactory.getInstance("X.509", provider);
+            }
+            else
+            {
+                certFact = CertificateFactory.getInstance("X.509");
+            }
+        }
+        catch (Exception e)
+        {
+            throw new IllegalArgumentException("can't create cert factory - " + e.toString());
+        }
+    }
+
+    private SubjectKeyIdentifier createSubjectKeyId(
+        PublicKey   pubKey)
+    {
+        try
+        {
+            SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+                (ASN1Sequence)new ASN1InputStream(pubKey.getEncoded()).readObject());
+
+            return new SubjectKeyIdentifier(info);
+        }
+        catch (Exception e)
+        {
+            throw new RuntimeException("error creating key");
+        }
+    }
+
+    public void setRandom(
+        SecureRandom    rand)
+    {
+        this.random = rand;
+    }
+
+    public Enumeration engineAliases() 
+    {
+        Hashtable  tab = new Hashtable();
+
+        Enumeration e = certs.keys();
+        while (e.hasMoreElements())
+        {
+            tab.put(e.nextElement(), "cert");
+        }
+
+        e = keys.keys();
+        while (e.hasMoreElements())
+        {
+            String  a = (String)e.nextElement();
+            if (tab.get(a) == null)
+            {
+                tab.put(a, "key");
+            }
+        }
+
+        return tab.keys();
+    }
+
+    public boolean engineContainsAlias(
+        String  alias) 
+    {
+        return (certs.get(alias) != null || keys.get(alias) != null);
+    }
+
+    /**
+     * this is quite complete - we should follow up on the chain, a bit
+     * tricky if a certificate appears in more than one chain...
+     */
+    public void engineDeleteEntry(
+        String  alias) 
+        throws KeyStoreException
+    {
+        Key k = (Key)keys.remove(alias);
+
+        Certificate c = (Certificate)certs.remove(alias);
+
+        if (c != null)
+        {
+            chainCerts.remove(new CertId(c.getPublicKey()));
+        }
+
+        if (k != null)
+        {
+            String  id = (String)localIds.remove(alias);
+            if (id != null)
+            {
+                c = (Certificate)keyCerts.remove(id);
+            }
+            if (c != null)
+            {
+                chainCerts.remove(new CertId(c.getPublicKey()));
+            }
+        }
+
+        if (c == null && k == null)
+        {
+            throw new KeyStoreException("no such entry as " + alias);
+        }
+    }
+
+    /**
+     * simply return the cert for the private key
+     */
+    public Certificate engineGetCertificate(
+        String alias) 
+    {
+        if (alias == null)
+        {
+            throw new IllegalArgumentException("null alias passed to getCertificate.");
+        }
+        
+        Certificate c = (Certificate)certs.get(alias);
+
+        //
+        // look up the key table - and try the local key id
+        //
+        if (c == null)
+        {
+            String  id = (String)localIds.get(alias);
+            if (id != null)
+            {
+                c = (Certificate)keyCerts.get(id);
+            }
+            else
+            {
+                c = (Certificate)keyCerts.get(alias);
+            }
+        }
+
+        return c;
+    }
+
+    public String engineGetCertificateAlias(
+        Certificate cert) 
+    {
+        Enumeration c = certs.elements();
+        Enumeration k = certs.keys();
+
+        while (c.hasMoreElements())
+        {
+            Certificate tc = (Certificate)c.nextElement();
+            String      ta = (String)k.nextElement();
+
+            if (tc.equals(cert))
+            {
+                return ta;
+            }
+        }
+
+        c = keyCerts.elements();
+        k = keyCerts.keys();
+
+        while (c.hasMoreElements())
+        {
+            Certificate tc = (Certificate)c.nextElement();
+            String      ta = (String)k.nextElement();
+
+            if (tc.equals(cert))
+            {
+                return ta;
+            }
+        }
+        
+        return null;
+    }
+    
+    public Certificate[] engineGetCertificateChain(
+        String alias) 
+    {
+        if (alias == null)
+        {
+            throw new IllegalArgumentException("null alias passed to getCertificateChain.");
+        }
+        
+        if (!engineIsKeyEntry(alias))
+        {
+            return null;
+        }
+        
+        Certificate c = engineGetCertificate(alias);
+
+        if (c != null)
+        {
+            Vector  cs = new Vector();
+
+            while (c != null)
+            {
+                X509Certificate     x509c = (X509Certificate)c;
+                Certificate         nextC = null;
+
+                byte[]  bytes = x509c.getExtensionValue(X509Extensions.AuthorityKeyIdentifier.getId());
+                if (bytes != null)
+                {
+                    try
+                    {
+                        ASN1InputStream         aIn = new ASN1InputStream(bytes);
+
+                        byte[] authBytes = ((ASN1OctetString)aIn.readObject()).getOctets();
+                        aIn = new ASN1InputStream(authBytes);
+
+                        AuthorityKeyIdentifier id = new AuthorityKeyIdentifier((ASN1Sequence)aIn.readObject());
+                        if (id.getKeyIdentifier() != null)
+                        {
+                            nextC = (Certificate)chainCerts.get(new CertId(id.getKeyIdentifier()));
+                        }
+                        
+                    }
+                    catch (IOException e)
+                    {
+                        throw new RuntimeException(e.toString());
+                    }
+                }
+
+                if (nextC == null)
+                {
+                    //
+                    // no authority key id, try the Issuer DN
+                    //
+                    Principal  i = x509c.getIssuerDN();
+                    Principal  s = x509c.getSubjectDN();
+
+                    if (!i.equals(s))
+                    {
+                        Enumeration e = chainCerts.keys();
+
+                        while (e.hasMoreElements())
+                        {
+                            X509Certificate crt = (X509Certificate)chainCerts.get(e.nextElement());
+                            Principal  sub = crt.getSubjectDN();
+                            if (sub.equals(i))
+                            {
+                                try
+                                {
+                                    x509c.verify(crt.getPublicKey());
+                                    nextC = crt;
+                                    break;
+                                }
+                                catch (Exception ex)
+                                {
+                                    // continue
+                                }
+                            }
+                        }
+                    }
+                }
+
+                cs.addElement(c);
+                if (nextC != c)     // self signed - end of the chain
+                {
+                    c = nextC;
+                }
+                else
+                {
+                    c = null;
+                }
+            }
+
+            Certificate[]   certChain = new Certificate[cs.size()];
+
+            for (int i = 0; i != certChain.length; i++)
+            {
+                certChain[i] = (Certificate)cs.elementAt(i);
+            }
+
+            return certChain;
+        }
+
+        return null;
+    }
+    
+    public Date engineGetCreationDate(String alias) 
+    {
+        return new Date();
+    }
+
+    public Key engineGetKey(
+        String alias,
+        char[] password) 
+        throws NoSuchAlgorithmException, UnrecoverableKeyException
+    {
+        if (alias == null)
+        {
+            throw new IllegalArgumentException("null alias passed to getKey.");
+        }
+        
+        return (Key)keys.get(alias);
+    }
+
+    public boolean engineIsCertificateEntry(
+        String alias) 
+    {
+        return (certs.get(alias) != null && keys.get(alias) == null);
+    }
+
+    public boolean engineIsKeyEntry(
+        String alias) 
+    {
+        return (keys.get(alias) != null);
+    }
+
+    public void engineSetCertificateEntry(
+        String      alias,
+        Certificate cert) 
+        throws KeyStoreException
+    {
+        if (certs.get(alias) != null)
+        {
+            throw new KeyStoreException("There is already a certificate with the name " + alias + ".");
+        }
+
+        certs.put(alias, cert);
+        chainCerts.put(new CertId(cert.getPublicKey()), cert);
+    }
+
+    public void engineSetKeyEntry(
+        String alias,
+        byte[] key,
+        Certificate[] chain) 
+        throws KeyStoreException
+    {
+        throw new RuntimeException("operation not supported");
+    }
+
+    public void engineSetKeyEntry(
+        String          alias,
+        Key             key,
+        char[]          password,
+        Certificate[]   chain) 
+        throws KeyStoreException
+    {
+        if ((key instanceof PrivateKey) && (chain == null))
+        {
+            throw new KeyStoreException("no certificate chain for private key");
+        }
+
+        if (keys.get(alias) != null && !key.equals(keys.get(alias)))
+        {
+            throw new KeyStoreException("There is already a key with the name " + alias + ".");
+        }
+
+        keys.put(alias, key);
+        certs.put(alias, chain[0]);
+
+        for (int i = 0; i != chain.length; i++)
+        {
+            chainCerts.put(new CertId(chain[i].getPublicKey()), chain[i]);
+        }
+    }
+
+    public int engineSize() 
+    {
+        Hashtable  tab = new Hashtable();
+
+        Enumeration e = certs.keys();
+        while (e.hasMoreElements())
+        {
+            tab.put(e.nextElement(), "cert");
+        }
+
+        e = keys.keys();
+        while (e.hasMoreElements())
+        {
+            String  a = (String)e.nextElement();
+            if (tab.get(a) == null)
+            {
+                tab.put(a, "key");
+            }
+        }
+
+        return tab.size();
+    }
+
+    protected PrivateKey unwrapKey(
+        AlgorithmIdentifier   algId,
+        byte[]                data,
+        char[]                password,
+        boolean               wrongPKCS12Zero)
+        throws IOException
+    {
+        String              algorithm = algId.getObjectId().getId();
+        PKCS12PBEParams     pbeParams = new PKCS12PBEParams((ASN1Sequence)algId.getParameters());
+
+        PBEKeySpec          pbeSpec = new PBEKeySpec(password);
+        PrivateKey          out = null;
+
+        try
+        {
+            SecretKeyFactory    keyFact = SecretKeyFactory.getInstance(
+                                                algorithm, "BC");
+            PBEParameterSpec    defParams = new PBEParameterSpec(
+                                                pbeParams.getIV(),
+                                                pbeParams.getIterations().intValue());
+
+            SecretKey           k = keyFact.generateSecret(pbeSpec);
+            
+            ((JCEPBEKey)k).setTryWrongPKCS12Zero(wrongPKCS12Zero);
+
+            Cipher cipher = Cipher.getInstance(algorithm, "BC");
+
+            cipher.init(Cipher.UNWRAP_MODE, k, defParams);
+
+            // we pass "" as the key algorithm type as it is unknown at this point
+            out = (PrivateKey)cipher.unwrap(data, "", Cipher.PRIVATE_KEY);
+        }
+        catch (Exception e)
+        {
+            throw new IOException("exception unwrapping private key - " + e.toString());
+        }
+
+        return out;
+    }
+
+    protected byte[] wrapKey(
+        String                  algorithm,
+        Key                     key,
+        PKCS12PBEParams         pbeParams,
+        char[]                  password)
+        throws IOException
+    {
+        PBEKeySpec          pbeSpec = new PBEKeySpec(password);
+        byte[]              out;
+
+        try
+        {
+            SecretKeyFactory    keyFact = SecretKeyFactory.getInstance(
+                                                algorithm, "BC");
+            PBEParameterSpec    defParams = new PBEParameterSpec(
+                                                pbeParams.getIV(),
+                                                pbeParams.getIterations().intValue());
+
+            Cipher cipher = Cipher.getInstance(algorithm, "BC");
+
+            cipher.init(Cipher.WRAP_MODE, keyFact.generateSecret(pbeSpec), defParams);
+
+            out = cipher.wrap(key);
+        }
+        catch (Exception e)
+        {
+            throw new IOException("exception encrypting data - " + e.toString());
+        }
+
+        return out;
+    }
+
+    protected ASN1Sequence decryptData(
+        AlgorithmIdentifier   algId,
+        byte[]                data,
+        char[]                password,
+        boolean               wrongPKCS12Zero)
+        throws IOException
+    {
+        String              algorithm = algId.getObjectId().getId();
+        PKCS12PBEParams     pbeParams = new PKCS12PBEParams((ASN1Sequence)algId.getParameters());
+
+        PBEKeySpec          pbeSpec = new PBEKeySpec(password);
+        byte[]              out = null;
+
+        try
+        {
+            SecretKeyFactory    keyFact = SecretKeyFactory.getInstance(
+                                                algorithm, "BC");
+            PBEParameterSpec    defParams = new PBEParameterSpec(
+                                                pbeParams.getIV(),
+                                                pbeParams.getIterations().intValue());
+            SecretKey           k = keyFact.generateSecret(pbeSpec);
+            
+            ((JCEPBEKey)k).setTryWrongPKCS12Zero(wrongPKCS12Zero);
+
+            Cipher cipher = Cipher.getInstance(algorithm, "BC");
+
+            cipher.init(Cipher.DECRYPT_MODE, k, defParams);
+
+            out = cipher.doFinal(data);
+        }
+        catch (Exception e)
+        {
+            throw new IOException("exception decrypting data - " + e.toString());
+        }
+
+        ASN1InputStream  aIn = new ASN1InputStream(out);
+
+        return (ASN1Sequence)aIn.readObject();
+    }
+
+    protected byte[] encryptData(
+        String                  algorithm,
+        byte[]                  data,
+        PKCS12PBEParams         pbeParams,
+        char[]                  password)
+        throws IOException
+    {
+        PBEKeySpec          pbeSpec = new PBEKeySpec(password);
+        byte[]              out;
+
+        try
+        {
+            SecretKeyFactory    keyFact = SecretKeyFactory.getInstance(
+                                                algorithm, "BC");
+            PBEParameterSpec    defParams = new PBEParameterSpec(
+                                                pbeParams.getIV(),
+                                                pbeParams.getIterations().intValue());
+
+            Cipher cipher = Cipher.getInstance(algorithm, "BC");
+
+            cipher.init(Cipher.ENCRYPT_MODE, keyFact.generateSecret(pbeSpec), defParams);
+
+            out = cipher.doFinal(data);
+        }
+        catch (Exception e)
+        {
+            throw new IOException("exception encrypting data - " + e.toString());
+        }
+
+        return out;
+    }
+
+    public void engineLoad(
+        InputStream stream,
+        char[]      password) 
+        throws IOException
+    {
+        if (stream == null)     // just initialising
+        {
+            return;
+        }
+
+        if (password == null)
+        {
+            throw new NullPointerException("No password supplied for PKCS#12 KeyStore.");
+        }
+
+        // BEGIN android-modified
+        BufferedInputStream             bufIn = new BufferedInputStream(stream, 8192);
+        // END android-modified
+
+        bufIn.mark(10);
+
+        int head = bufIn.read();
+
+        if (head != 0x30)
+        {
+            throw new IOException("stream does not represent a PKCS12 key store");
+        }
+
+        bufIn.reset();
+
+        ASN1InputStream bIn = new ASN1InputStream(bufIn);
+        ASN1Sequence    obj = (ASN1Sequence)bIn.readObject();
+        Pfx             bag = new Pfx(obj);
+        ContentInfo     info = bag.getAuthSafe();
+        Vector          chain = new Vector();
+        boolean         unmarkedKey = false;
+        boolean         wrongPKCS12Zero = false;
+
+        if (bag.getMacData() != null)           // check the mac code
+        {
+            ByteArrayOutputStream       bOut = new ByteArrayOutputStream();
+            BEROutputStream             berOut = new BEROutputStream(bOut);
+            MacData                     mData = bag.getMacData();
+            DigestInfo                  dInfo = mData.getMac();
+            AlgorithmIdentifier         algId = dInfo.getAlgorithmId();
+            byte[]                      salt = mData.getSalt();
+            int                         itCount = mData.getIterationCount().intValue();
+        
+            berOut.writeObject(info);
+
+            byte[]  data = ((ASN1OctetString)info.getContent()).getOctets();
+
+            try
+            {
+                Mac                 mac = Mac.getInstance(algId.getObjectId().getId(), "BC");
+                SecretKeyFactory    keyFact = SecretKeyFactory.getInstance(algId.getObjectId().getId(), "BC");
+                PBEParameterSpec    defParams = new PBEParameterSpec(salt, itCount);
+                PBEKeySpec          pbeSpec = new PBEKeySpec(password);
+
+                mac.init(keyFact.generateSecret(pbeSpec), defParams);
+
+                mac.update(data);
+
+                byte[]  res = mac.doFinal();
+                byte[]  dig = dInfo.getDigest();
+
+                if (res.length != dInfo.getDigest().length)
+                {
+                    throw new IOException("PKCS12 key store mac invalid - wrong password or corrupted file.");
+                }
+
+                boolean okay = true;
+                
+                for (int i = 0; i != res.length; i++)
+                {
+                    if (res[i] != dig[i])
+                    {
+                        if (password.length != 0)  // may be dodgey zero password
+                        {
+                            throw new IOException("PKCS12 key store mac invalid - wrong password or corrupted file.");
+                        }
+                        else
+                        {
+                            okay = false;
+                            break;
+                        }
+                    }
+                }
+                
+                //
+                // may be incorrect zero length password
+                //
+                if (!okay)
+                {
+                    SecretKey k = keyFact.generateSecret(pbeSpec);
+                    
+                    ((JCEPBEKey)k).setTryWrongPKCS12Zero(true);
+                    
+                    mac.init(k, defParams);
+    
+                    mac.update(data);
+    
+                    res = mac.doFinal();
+                    dig = dInfo.getDigest();
+                    
+                    for (int i = 0; i != res.length; i++)
+                    {
+                        if (res[i] != dig[i])
+                        {
+                           throw new IOException("PKCS12 key store mac invalid - wrong password or corrupted file.");
+                        }
+                    }
+                    
+                    wrongPKCS12Zero = true;
+                }
+            }
+            catch (IOException e)
+            {
+                throw e;
+            }
+            catch (Exception e)
+            {
+                throw new IOException("error constructing MAC: " + e.toString());
+            }
+        }
+
+        keys = new Hashtable();
+        localIds = new Hashtable();
+
+        if (info.getContentType().equals(data))
+        {
+            bIn = new ASN1InputStream(((ASN1OctetString)info.getContent()).getOctets());
+
+            AuthenticatedSafe   authSafe = new AuthenticatedSafe((ASN1Sequence)bIn.readObject());
+            ContentInfo[]       c = authSafe.getContentInfo();
+
+            for (int i = 0; i != c.length; i++)
+            {
+                if (c[i].getContentType().equals(data))
+                {
+                    ASN1InputStream dIn = new ASN1InputStream(((ASN1OctetString)c[i].getContent()).getOctets());
+                    ASN1Sequence    seq = (ASN1Sequence)dIn.readObject();
+
+                    for (int j = 0; j != seq.size(); j++)
+                    {
+                        SafeBag b = new SafeBag((ASN1Sequence)seq.getObjectAt(j));
+                        if (b.getBagId().equals(pkcs8ShroudedKeyBag))
+                        {
+                            org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = new org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo((ASN1Sequence)b.getBagValue());
+                            PrivateKey              privKey = unwrapKey(eIn.getEncryptionAlgorithm(), eIn.getEncryptedData(), password, wrongPKCS12Zero);
+
+                            //
+                            // set the attributes on the key
+                            //
+                            PKCS12BagAttributeCarrier   bagAttr = (PKCS12BagAttributeCarrier)privKey;
+                            String                                   alias = null;
+                            ASN1OctetString                   localId = null;
+
+                            if (b.getBagAttributes() != null)
+                            {
+                                Enumeration e = b.getBagAttributes().getObjects();
+                                while (e.hasMoreElements())
+                                {
+                                    ASN1Sequence  sq = (ASN1Sequence)e.nextElement();
+                                    DERObjectIdentifier     aOid = (DERObjectIdentifier)sq.getObjectAt(0);
+                                    ASN1Set                 attrSet = (ASN1Set)sq.getObjectAt(1);
+                                    DERObject               attr = null;
+    
+                                    if (attrSet.size() > 0)
+                                    {
+                                        attr = (DERObject)attrSet.getObjectAt(0);
+    
+                                        bagAttr.setBagAttribute(aOid, attr);
+                                    }
+    
+                                    if (aOid.equals(pkcs_9_at_friendlyName))
+                                    {
+                                        alias = ((DERBMPString)attr).getString();
+                                        keys.put(alias, privKey);
+                                    }
+                                    else if (aOid.equals(pkcs_9_at_localKeyId))
+                                    {
+                                        localId = (ASN1OctetString)attr;
+                                    }
+                                }
+                            }
+                        
+                            if (localId != null)
+                            {
+                                String name = new String(Hex.encode(localId.getOctets()));
+    
+                                if (alias == null)
+                                {
+                                    keys.put(name, privKey);
+                                }
+                                else
+                                {
+                                    localIds.put(alias, name);
+                                }
+                             }
+                             else
+                             {
+                                 unmarkedKey = true;
+                                 keys.put("unmarked", privKey);
+                             }
+                        }
+                        else if (b.getBagId().equals(certBag))
+                        {
+                            chain.addElement(b);
+                        }
+                        else
+                        {
+                            System.out.println("extra in data " + b.getBagId());
+                            System.out.println(ASN1Dump.dumpAsString(b));
+                        }
+                    }
+                }
+                else if (c[i].getContentType().equals(encryptedData))
+                {
+                    EncryptedData d = new EncryptedData((ASN1Sequence)c[i].getContent());
+                    ASN1Sequence seq = decryptData(d.getEncryptionAlgorithm(), d.getContent().getOctets(), password, wrongPKCS12Zero);
+
+                    for (int j = 0; j != seq.size(); j++)
+                    {
+                        SafeBag b = new SafeBag((ASN1Sequence)seq.getObjectAt(j));
+                        
+                        if (b.getBagId().equals(certBag))
+                        {
+                            chain.addElement(b);
+                        }
+                        else if (b.getBagId().equals(pkcs8ShroudedKeyBag))
+                        {
+                            org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = new org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo((ASN1Sequence)b.getBagValue());
+                            PrivateKey              privKey = unwrapKey(eIn.getEncryptionAlgorithm(), eIn.getEncryptedData(), password, wrongPKCS12Zero);
+
+                            //
+                            // set the attributes on the key
+                            //
+                            PKCS12BagAttributeCarrier   bagAttr = (PKCS12BagAttributeCarrier)privKey;
+                            String                      alias = null;
+                            ASN1OctetString              localId = null;
+
+                            Enumeration e = b.getBagAttributes().getObjects();
+                            while (e.hasMoreElements())
+                            {
+                                ASN1Sequence  sq = (ASN1Sequence)e.nextElement();
+                                DERObjectIdentifier     aOid = (DERObjectIdentifier)sq.getObjectAt(0);
+                                ASN1Set                 attrSet= (ASN1Set)sq.getObjectAt(1);
+                                DERObject               attr = null;
+
+                                if (attrSet.size() > 0)
+                                {
+                                    attr = (DERObject)attrSet.getObjectAt(0);
+
+                                    bagAttr.setBagAttribute(aOid, attr);
+                                }
+
+                                if (aOid.equals(pkcs_9_at_friendlyName))
+                                {
+                                    alias = ((DERBMPString)attr).getString();
+                                    keys.put(alias, privKey);
+                                }
+                                else if (aOid.equals(pkcs_9_at_localKeyId))
+                                {
+                                    localId = (ASN1OctetString)attr;
+                                }
+                            }
+
+                            String name = new String(Hex.encode(localId.getOctets()));
+
+                            if (alias == null)
+                            {
+                                keys.put(name, privKey);
+                            }
+                            else
+                            {
+                                localIds.put(alias, name);
+                            }
+                        }
+                        else if (b.getBagId().equals(keyBag))
+                        {
+                            org.bouncycastle.asn1.pkcs.PrivateKeyInfo pIn = new org.bouncycastle.asn1.pkcs.PrivateKeyInfo((ASN1Sequence)b.getBagValue());
+                            PrivateKey              privKey = JDKKeyFactory.createPrivateKeyFromPrivateKeyInfo(pIn);
+
+                            //
+                            // set the attributes on the key
+                            //
+                            PKCS12BagAttributeCarrier   bagAttr = (PKCS12BagAttributeCarrier)privKey;
+                            String                      alias = null;
+                            ASN1OctetString             localId = null;
+
+                            Enumeration e = b.getBagAttributes().getObjects();
+                            while (e.hasMoreElements())
+                            {
+                                ASN1Sequence  sq = (ASN1Sequence)e.nextElement();
+                                DERObjectIdentifier     aOid = (DERObjectIdentifier)sq.getObjectAt(0);
+                                ASN1Set                 attrSet = (ASN1Set)sq.getObjectAt(1);
+                                DERObject   attr = null;
+
+                                if (attrSet.size() > 0)
+                                {
+                                    attr = (DERObject)attrSet.getObjectAt(0);
+
+                                    bagAttr.setBagAttribute(aOid, attr);
+                                }
+
+                                if (aOid.equals(pkcs_9_at_friendlyName))
+                                {
+                                    alias = ((DERBMPString)attr).getString();
+                                    keys.put(alias, privKey);
+                                }
+                                else if (aOid.equals(pkcs_9_at_localKeyId))
+                                {
+                                    localId = (ASN1OctetString)attr;
+                                }
+                            }
+
+                            String name = new String(Hex.encode(localId.getOctets()));
+
+                            if (alias == null)
+                            {
+                                keys.put(name, privKey);
+                            }
+                            else
+                            {
+                                localIds.put(alias, name);
+                            }
+                        }
+                        else
+                        {
+                            System.out.println("extra in encryptedData " + b.getBagId());
+                            System.out.println(ASN1Dump.dumpAsString(b));
+                        }
+                    }
+                }
+                else
+                {
+                    System.out.println("extra " + c[i].getContentType().getId());
+                    System.out.println("extra " + ASN1Dump.dumpAsString(c[i].getContent()));
+                }
+            }
+        }
+
+        certs = new Hashtable();
+        chainCerts = new Hashtable();
+        keyCerts = new Hashtable();
+
+        for (int i = 0; i != chain.size(); i++)
+        {
+            SafeBag     b = (SafeBag)chain.elementAt(i);
+            CertBag     cb = new CertBag((ASN1Sequence)b.getBagValue());
+            Certificate cert = null;
+
+            try
+            {
+                ByteArrayInputStream  cIn = new ByteArrayInputStream(
+                                ((ASN1OctetString)cb.getCertValue()).getOctets());
+                cert = certFact.generateCertificate(cIn);
+            }
+            catch (Exception e)
+            {
+                throw new RuntimeException(e.toString());
+            }
+
+
+            //
+            // set the attributes
+            //
+            ASN1OctetString              localId = null;
+            String                      alias = null;
+
+            if (b.getBagAttributes() != null)
+            {
+                Enumeration e = b.getBagAttributes().getObjects();
+                while (e.hasMoreElements())
+                {
+                    ASN1Sequence  sq = (ASN1Sequence)e.nextElement();
+                    DERObjectIdentifier     oid = (DERObjectIdentifier)sq.getObjectAt(0);
+                    DERObject               attr = (DERObject)((ASN1Set)sq.getObjectAt(1)).getObjectAt(0);
+
+                    if (cert instanceof PKCS12BagAttributeCarrier)
+                    {
+                        PKCS12BagAttributeCarrier   bagAttr = (PKCS12BagAttributeCarrier)cert;
+                        bagAttr.setBagAttribute(oid, attr);
+                    }
+
+                    if (oid.equals(pkcs_9_at_friendlyName))
+                    {
+                        alias = ((DERBMPString)attr).getString();
+                    }
+                    else if (oid.equals(pkcs_9_at_localKeyId))
+                    {
+                        localId = (ASN1OctetString)attr;
+                    }
+                }
+            }
+
+            chainCerts.put(new CertId(cert.getPublicKey()), cert);
+
+            if (unmarkedKey)
+            {
+                if (keyCerts.isEmpty())
+                {
+                    String    name = new String(Hex.encode(createSubjectKeyId(cert.getPublicKey()).getKeyIdentifier()));
+                    
+                    keyCerts.put(name, cert);
+                    keys.put(name, keys.remove("unmarked"));
+                }
+            }
+            else
+            {
+                //
+                // the local key id needs to override the friendly name
+                //
+                if (localId != null)
+                {
+                    String name = new String(Hex.encode(localId.getOctets()));
+
+                    keyCerts.put(name, cert);
+                }
+                if (alias != null)
+                {
+                    certs.put(alias, cert);
+                }
+            }
+        }
+    }
+
+    public void engineStore(OutputStream stream, char[] password) 
+        throws IOException
+    {
+        if (password == null)
+        {
+            throw new NullPointerException("No password supplied for PKCS#12 KeyStore.");
+        }
+
+        ContentInfo[]   c = new ContentInfo[2];
+
+
+        //
+        // handle the key
+        //
+        ASN1EncodableVector  keyS = new ASN1EncodableVector();
+
+
+        Enumeration ks = keys.keys();
+
+        while (ks.hasMoreElements())
+        {
+            byte[]                  kSalt = new byte[SALT_SIZE];
+
+            random.nextBytes(kSalt);
+
+            String                  name = (String)ks.nextElement();
+            PrivateKey              privKey = (PrivateKey)keys.get(name);
+            PKCS12PBEParams         kParams = new PKCS12PBEParams(kSalt, MIN_ITERATIONS);
+            byte[]                  kBytes = wrapKey(KEY_ALGORITHM, privKey, kParams, password);
+            AlgorithmIdentifier     kAlgId = new AlgorithmIdentifier(new DERObjectIdentifier(KEY_ALGORITHM), kParams.getDERObject());
+            org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo kInfo = new org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo(kAlgId, kBytes);
+            boolean                 attrSet = false;
+            ASN1EncodableVector     kName = new ASN1EncodableVector();
+
+            if (privKey instanceof PKCS12BagAttributeCarrier)
+            {
+                PKCS12BagAttributeCarrier   bagAttrs = (PKCS12BagAttributeCarrier)privKey;
+                //
+                // make sure we are using the local alias on store
+                //
+                DERBMPString    nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+                if (nm == null || !nm.getString().equals(name))
+                {
+                    bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(name));
+                }
+
+                //
+                // make sure we have a local key-id
+                //
+                if (bagAttrs.getBagAttribute(pkcs_9_at_localKeyId) == null)
+                {
+                    Certificate             ct = engineGetCertificate(name);
+
+                    bagAttrs.setBagAttribute(pkcs_9_at_localKeyId, createSubjectKeyId(ct.getPublicKey()));
+                }
+
+                Enumeration e = bagAttrs.getBagAttributeKeys();
+
+                while (e.hasMoreElements())
+                {
+                    DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+                    ASN1EncodableVector  kSeq = new ASN1EncodableVector();
+
+                    kSeq.add(oid);
+                    kSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+
+                    attrSet = true;
+
+                    kName.add(new DERSequence(kSeq));
+                }
+            }
+
+            if (!attrSet)
+            {
+                //
+                // set a default friendly name (from the key id) and local id
+                //
+                ASN1EncodableVector     kSeq = new ASN1EncodableVector();
+                Certificate             ct = engineGetCertificate(name);
+
+                kSeq.add(pkcs_9_at_localKeyId);
+                kSeq.add(new DERSet(createSubjectKeyId(ct.getPublicKey())));
+
+                kName.add(new DERSequence(kSeq));
+
+                kSeq = new ASN1EncodableVector();
+
+                kSeq.add(pkcs_9_at_friendlyName);
+                kSeq.add(new DERSet(new DERBMPString(name)));
+
+                kName.add(new DERSequence(kSeq));
+            }
+
+            SafeBag                 kBag = new SafeBag(pkcs8ShroudedKeyBag, kInfo.getDERObject(), new DERSet(kName));
+            keyS.add(kBag);
+        }
+
+        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+        DEROutputStream         dOut = new DEROutputStream(bOut);
+
+        dOut.writeObject(new DERSequence(keyS));
+
+        BERConstructedOctetString          keyString = new BERConstructedOctetString(bOut.toByteArray());
+
+        //
+        // certficate processing
+        //
+        byte[]                  cSalt = new byte[SALT_SIZE];
+
+        random.nextBytes(cSalt);
+
+        ASN1EncodableVector  certSeq = new ASN1EncodableVector();
+        PKCS12PBEParams         cParams = new PKCS12PBEParams(cSalt, MIN_ITERATIONS);
+        AlgorithmIdentifier     cAlgId = new AlgorithmIdentifier(new DERObjectIdentifier(CERT_ALGORITHM), cParams.getDERObject());
+        Hashtable               doneCerts = new Hashtable();
+
+        Enumeration cs = keys.keys();
+        while (cs.hasMoreElements())
+        {
+            try
+            {
+                String              name = (String)cs.nextElement();
+                Certificate         cert = engineGetCertificate(name);
+                boolean             cAttrSet = false;
+                CertBag             cBag = new CertBag(
+                                        x509certType,
+                                        new DEROctetString(cert.getEncoded()));
+                ASN1EncodableVector fName = new ASN1EncodableVector();
+
+                if (cert instanceof PKCS12BagAttributeCarrier)
+                {
+                    PKCS12BagAttributeCarrier   bagAttrs = (PKCS12BagAttributeCarrier)cert;
+                    //
+                    // make sure we are using the local alias on store
+                    //
+                    DERBMPString    nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+                    if (nm == null || !nm.getString().equals(name))
+                    {
+                        bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(name));
+                    }
+
+                    //
+                    // make sure we have a local key-id
+                    //
+                    if (bagAttrs.getBagAttribute(pkcs_9_at_localKeyId) == null)
+                    {
+                        bagAttrs.setBagAttribute(pkcs_9_at_localKeyId, createSubjectKeyId(cert.getPublicKey()));
+                    }
+
+                    Enumeration e = bagAttrs.getBagAttributeKeys();
+
+                    while (e.hasMoreElements())
+                    {
+                        DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+                        ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+                        fSeq.add(oid);
+                        fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+                        fName.add(new DERSequence(fSeq));
+
+                        cAttrSet = true;
+                    }
+                }
+
+                if (!cAttrSet)
+                {
+                    ASN1EncodableVector  fSeq = new ASN1EncodableVector();
+
+                    fSeq.add(pkcs_9_at_localKeyId);
+                    fSeq.add(new DERSet(createSubjectKeyId(cert.getPublicKey())));
+                    fName.add(new DERSequence(fSeq));
+
+                    fSeq = new ASN1EncodableVector();
+
+                    fSeq.add(pkcs_9_at_friendlyName);
+                    fSeq.add(new DERSet(new DERBMPString(name)));
+
+                    fName.add(new DERSequence(fSeq));
+                }
+
+                SafeBag sBag = new SafeBag(certBag, cBag.getDERObject(), new DERSet(fName));
+
+                certSeq.add(sBag);
+
+                doneCerts.put(cert, cert);
+            }
+            catch (CertificateEncodingException e)
+            {
+                throw new IOException("Error encoding certificate: " + e.toString());
+            }
+        }
+
+        cs = certs.keys();
+        while (cs.hasMoreElements())
+        {
+            try
+            {
+                String              certId = (String)cs.nextElement();
+                Certificate         cert = (Certificate)certs.get(certId);
+                boolean             cAttrSet = false;
+
+                if (keys.get(certId) != null)
+                {
+                    continue;
+                }
+
+                CertBag             cBag = new CertBag(
+                                        x509certType,
+                                        new DEROctetString(cert.getEncoded()));
+                ASN1EncodableVector fName = new ASN1EncodableVector();
+
+                if (cert instanceof PKCS12BagAttributeCarrier)
+                {
+                    PKCS12BagAttributeCarrier   bagAttrs = (PKCS12BagAttributeCarrier)cert;
+                    //
+                    // make sure we are using the local alias on store
+                    //
+                    DERBMPString    nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+                    if (nm == null || !nm.getString().equals(certId))
+                    {
+                        bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(certId));
+                    }
+
+                    Enumeration e = bagAttrs.getBagAttributeKeys();
+
+                    while (e.hasMoreElements())
+                    {
+                        DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+                        ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+                        fSeq.add(oid);
+                        fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+                        fName.add(new DERSequence(fSeq));
+
+                        cAttrSet = true;
+                    }
+                }
+
+                if (!cAttrSet)
+                {
+                    ASN1EncodableVector  fSeq = new ASN1EncodableVector();
+
+                    fSeq.add(pkcs_9_at_friendlyName);
+                    fSeq.add(new DERSet(new DERBMPString(certId)));
+
+                    fName.add(new DERSequence(fSeq));
+                }
+
+                SafeBag sBag = new SafeBag(certBag, cBag.getDERObject(), new DERSet(fName));
+
+                certSeq.add(sBag);
+
+                doneCerts.put(cert, cert);
+            }
+            catch (CertificateEncodingException e)
+            {
+                throw new IOException("Error encoding certificate: " + e.toString());
+            }
+        }
+
+        cs = chainCerts.keys();
+        while (cs.hasMoreElements())
+        {
+            try
+            {
+                CertId              certId = (CertId)cs.nextElement();
+                Certificate         cert = (Certificate)chainCerts.get(certId);
+
+                if (doneCerts.get(cert) != null)
+                {
+                    continue;
+                }
+
+                CertBag             cBag = new CertBag(
+                                        x509certType,
+                                        new DEROctetString(cert.getEncoded()));
+                ASN1EncodableVector fName = new ASN1EncodableVector();
+
+                if (cert instanceof PKCS12BagAttributeCarrier)
+                {
+                    PKCS12BagAttributeCarrier   bagAttrs = (PKCS12BagAttributeCarrier)cert;
+                    Enumeration e = bagAttrs.getBagAttributeKeys();
+
+                    while (e.hasMoreElements())
+                    {
+                        DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+                        ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+                        fSeq.add(oid);
+                        fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+                        fName.add(new DERSequence(fSeq));
+                    }
+                }
+
+                SafeBag sBag = new SafeBag(certBag, cBag.getDERObject(), new DERSet(fName));
+
+                certSeq.add(sBag);
+            }
+            catch (CertificateEncodingException e)
+            {
+                throw new IOException("Error encoding certificate: " + e.toString());
+            }
+        }
+
+        bOut.reset();
+
+        dOut = new DEROutputStream(bOut);
+
+        dOut.writeObject(new DERSequence(certSeq));
+
+        dOut.close();
+
+        byte[]                  certBytes = encryptData(CERT_ALGORITHM, bOut.toByteArray(), cParams, password);
+        EncryptedData           cInfo = new EncryptedData(data, cAlgId, new BERConstructedOctetString(certBytes));
+
+        c[0] = new ContentInfo(data, keyString);
+
+        c[1] = new ContentInfo(encryptedData, cInfo.getDERObject());
+
+        AuthenticatedSafe   auth = new AuthenticatedSafe(c);
+
+        bOut.reset();
+
+        BEROutputStream         berOut = new BEROutputStream(bOut);
+
+        berOut.writeObject(auth);
+
+        byte[]              pkg = bOut.toByteArray();
+
+        ContentInfo         mainInfo = new ContentInfo(data, new BERConstructedOctetString(pkg));
+
+        //
+        // create the mac
+        //
+        byte[]                      mSalt = new byte[20];
+        int                         itCount = MIN_ITERATIONS;
+
+        random.nextBytes(mSalt);
+    
+        byte[]  data = ((ASN1OctetString)mainInfo.getContent()).getOctets();
+
+        MacData                 mData = null;
+
+        try
+        {
+            Mac                 mac = Mac.getInstance(id_SHA1.getId(), "BC");
+            SecretKeyFactory    keyFact = SecretKeyFactory.getInstance(id_SHA1.getId(), "BC");
+            PBEParameterSpec    defParams = new PBEParameterSpec(mSalt, itCount);
+            PBEKeySpec          pbeSpec = new PBEKeySpec(password);
+
+            mac.init(keyFact.generateSecret(pbeSpec), defParams);
+
+            mac.update(data);
+
+            byte[]      res = mac.doFinal();
+
+            // BEGIN android-changed
+            AlgorithmIdentifier     algId = new AlgorithmIdentifier(id_SHA1, DERNull.THE_ONE);
+            // END android-changed
+            DigestInfo              dInfo = new DigestInfo(algId, res);
+
+            mData = new MacData(dInfo, mSalt, itCount);
+        }
+        catch (Exception e)
+        {
+            throw new IOException("error constructing MAC: " + e.toString());
+        }
+        
+        //
+        // output the Pfx
+        //
+        Pfx                 pfx = new Pfx(mainInfo, mData);
+
+        berOut = new BEROutputStream(stream);
+
+        berOut.writeObject(pfx);
+    }
+
+    public static class BCPKCS12KeyStore
+        extends JDKPKCS12KeyStore
+    {
+        public BCPKCS12KeyStore()
+        {
+            super("BC");
+        }
+    }
+
+    public static class DefPKCS12KeyStore
+        extends JDKPKCS12KeyStore
+    {
+        public DefPKCS12KeyStore()
+        {
+            super(null);
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKPSSSigner.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKPSSSigner.java
new file mode 100644
index 0000000..33df9fd
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKPSSSigner.java
@@ -0,0 +1,289 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.MGF1ParameterSpec;
+import java.security.spec.PSSParameterSpec;
+
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.CryptoException;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.engines.RSAEngine;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.crypto.signers.PSSSigner;
+
+public class JDKPSSSigner
+    extends Signature
+{
+    private AlgorithmParameters    engineParams;
+    private PSSParameterSpec       paramSpec;
+    private PSSParameterSpec       originalSpec;
+    private AsymmetricBlockCipher  signer;
+    private Digest digest;
+    private int saltLength;
+    private byte trailer;
+
+    private PSSSigner pss;
+
+    private byte getTrailer(
+        int trailerField)
+    {
+        if (trailerField == 1)
+        {
+            return PSSSigner.TRAILER_IMPLICIT;
+        }
+        
+        throw new IllegalArgumentException("unknown trailer field");
+    }
+    
+    protected JDKPSSSigner(
+        String                name,
+        AsymmetricBlockCipher signer,
+        PSSParameterSpec      paramSpec)
+    {
+        super(name);
+
+        this.signer = signer;
+        
+        if (paramSpec == null)
+        {
+            originalSpec = null;
+            paramSpec = PSSParameterSpec.DEFAULT;
+        }
+        else
+        {
+            originalSpec = paramSpec;
+            this.paramSpec = paramSpec;
+        }
+        
+        this.digest = JCEDigestUtil.getDigest(paramSpec.getDigestAlgorithm());
+        this.saltLength = paramSpec.getSaltLength();
+        this.trailer = getTrailer(paramSpec.getTrailerField());
+    }
+    
+    protected void engineInitVerify(
+        PublicKey   publicKey)
+        throws InvalidKeyException
+    {
+        if (!(publicKey instanceof RSAPublicKey))
+        {
+            throw new InvalidKeyException("Supplied key is not a RSAPublicKey instance");
+        }
+
+        pss = new PSSSigner(signer, digest, saltLength);
+        pss.init(false,
+            RSAUtil.generatePublicKeyParameter((RSAPublicKey)publicKey));
+    }
+
+    protected void engineInitSign(
+        PrivateKey      privateKey,
+        SecureRandom    random)
+        throws InvalidKeyException
+    {
+        if (!(privateKey instanceof RSAPrivateKey))
+        {
+            throw new InvalidKeyException("Supplied key is not a RSAPrivateKey instance");
+        }
+
+        pss = new PSSSigner(signer, digest, saltLength, trailer);
+        pss.init(true, new ParametersWithRandom(RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey), random));
+    }
+
+    protected void engineInitSign(
+        PrivateKey  privateKey)
+        throws InvalidKeyException
+    {
+        if (!(privateKey instanceof RSAPrivateKey))
+        {
+            throw new InvalidKeyException("Supplied key is not a RSAPrivateKey instance");
+        }
+
+        pss = new PSSSigner(signer, digest, saltLength, trailer);
+        pss.init(true, RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey));
+    }
+
+    protected void engineUpdate(
+        byte    b)
+        throws SignatureException
+    {
+        pss.update(b);
+    }
+
+    protected void engineUpdate(
+        byte[]  b,
+        int     off,
+        int     len) 
+        throws SignatureException
+    {
+        pss.update(b, off, len);
+    }
+
+    protected byte[] engineSign()
+        throws SignatureException
+    {
+        try
+        {
+            return pss.generateSignature();
+        }
+        catch (CryptoException e)
+        {
+            throw new SignatureException(e.getMessage());
+        }
+    }
+
+    protected boolean engineVerify(
+        byte[]  sigBytes) 
+        throws SignatureException
+    {
+        return pss.verifySignature(sigBytes);
+    }
+
+    protected void engineSetParameter(
+        AlgorithmParameterSpec params)
+        throws InvalidParameterException
+    {
+        if (params instanceof PSSParameterSpec)
+        {
+            paramSpec = (PSSParameterSpec)params;
+            
+            if (originalSpec != null)
+            {
+                if (!JCEDigestUtil.isSameDigest(originalSpec.getDigestAlgorithm(), paramSpec.getDigestAlgorithm()))
+                {
+                    throw new InvalidParameterException("parameter must be using " + originalSpec.getDigestAlgorithm());
+                }
+            }
+            if (!paramSpec.getMGFAlgorithm().equalsIgnoreCase("MGF1") && !paramSpec.getMGFAlgorithm().equals(PKCSObjectIdentifiers.id_mgf1.getId()))
+            {
+                throw new InvalidParameterException("unknown mask generation function specified");
+            }
+            
+            if (!(paramSpec.getMGFParameters() instanceof MGF1ParameterSpec))
+            {
+                throw new InvalidParameterException("unkown MGF parameters");
+            }
+            
+            MGF1ParameterSpec   mgfParams = (MGF1ParameterSpec)paramSpec.getMGFParameters();
+            
+            if (!JCEDigestUtil.isSameDigest(mgfParams.getDigestAlgorithm(), paramSpec.getDigestAlgorithm()))
+            {
+                throw new InvalidParameterException("digest algorithm for MGF should be the same as for PSS parameters.");
+            }
+            
+            digest = JCEDigestUtil.getDigest(mgfParams.getDigestAlgorithm());
+            
+            if (digest == null)
+            {
+                throw new InvalidParameterException("no match on MGF digest algorithm: "+ mgfParams.getDigestAlgorithm());
+            }
+            
+            this.saltLength = paramSpec.getSaltLength();
+            this.trailer = getTrailer(paramSpec.getTrailerField());
+        }
+        else
+        {
+            throw new InvalidParameterException("Only PSSParameterSpec supported");
+        }
+    }
+
+    protected AlgorithmParameters engineGetParameters() 
+    {
+        if (engineParams == null)
+        {
+            if (paramSpec != null)
+            {
+                try
+                {
+                    engineParams = AlgorithmParameters.getInstance("PSS", "BC");
+                    engineParams.init(paramSpec);
+                }
+                catch (Exception e)
+                {
+                    throw new RuntimeException(e.toString());
+                }
+            }
+        }
+
+        return engineParams;
+    }
+    
+    /**
+     * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+     */
+    protected void engineSetParameter(
+        String  param,
+        Object  value)
+    {
+        throw new UnsupportedOperationException("engineSetParameter unsupported");
+    }
+    
+    protected Object engineGetParameter(
+        String param)
+    {
+        throw new UnsupportedOperationException("engineGetParameter unsupported");
+    }
+
+    static public class PSSwithRSA
+        extends JDKPSSSigner
+    {
+        public PSSwithRSA()
+        {
+            super("SHA1withRSAandMGF1", new RSAEngine(), null);
+        }
+    }
+    
+    static public class SHA1withRSA
+        extends JDKPSSSigner
+    {
+        public SHA1withRSA()
+        {
+            super("SHA1withRSAandMGF1", new RSAEngine(), PSSParameterSpec.DEFAULT);
+        }
+    }
+
+    static public class SHA224withRSA
+        extends JDKPSSSigner
+    {
+        public SHA224withRSA()
+        {
+            super("SHA2224withRSAandMGF1", new RSAEngine(), new PSSParameterSpec("SHA-224", "MGF1", new MGF1ParameterSpec("SHA-224"), 28, 1));
+        }
+    }
+    
+    static public class SHA256withRSA
+        extends JDKPSSSigner
+    {
+        public SHA256withRSA()
+        {
+            super("SHA256withRSAandMGF1", new RSAEngine(), new PSSParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), 32, 1));
+        }
+    }
+
+    static public class SHA384withRSA
+        extends JDKPSSSigner
+    {
+        public SHA384withRSA()
+        {
+            super("SHA384withRSAandMGF1", new RSAEngine(), new PSSParameterSpec("SHA-384", "MGF1", new MGF1ParameterSpec("SHA-384"), 48, 1));
+        }
+    }
+
+    static public class SHA512withRSA
+        extends JDKPSSSigner
+    {
+        public SHA512withRSA()
+        {
+            super("SHA512withRSAandMGF1", new RSAEngine(), new PSSParameterSpec("SHA-512", "MGF1", new MGF1ParameterSpec("SHA-512"), 64, 1));
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKX509CertificateFactory.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKX509CertificateFactory.java
new file mode 100644
index 0000000..899cdd0
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKX509CertificateFactory.java
@@ -0,0 +1,475 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+import java.security.cert.CertPath;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactorySpi;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.SignedData;
+import org.bouncycastle.asn1.x509.CertificateList;
+import org.bouncycastle.asn1.x509.X509CertificateStructure;
+import org.bouncycastle.util.encoders.Base64;
+
+/**
+ * class for dealing with X509 certificates.
+ * <p>
+ * At the moment this will deal with "-----BEGIN CERTIFICATE-----" to "-----END CERTIFICATE-----"
+ * base 64 encoded certs, as well as the BER binaries of certificates and some classes of PKCS#7
+ * objects.
+ */
+public class JDKX509CertificateFactory
+    extends CertificateFactorySpi
+{
+    private static final long  MAX_MEMORY = Runtime.getRuntime().maxMemory();
+    
+    private SignedData         sData = null;
+    private int                sDataObjectCount = 0;
+    private InputStream        currentStream = null;
+    
+    private SignedData         sCrlData = null;
+    private int                sCrlDataObjectCount = 0;
+    private InputStream        currentCrlStream = null;
+
+    private int getLimit(InputStream in)
+        throws IOException
+    {
+        if (in instanceof ByteArrayInputStream)
+        {
+            return in.available();
+        }
+        
+        if (MAX_MEMORY > Integer.MAX_VALUE)
+        {
+            return Integer.MAX_VALUE;
+        }
+        
+        return (int)MAX_MEMORY;
+    }
+    
+    private String readLine(
+        InputStream in)
+        throws IOException
+    {
+        int             c;
+        StringBuffer    l = new StringBuffer();
+
+        while (((c = in.read()) != '\n') && (c >= 0))
+        {
+            if (c == '\r')
+            {
+                continue;
+            }
+
+            l.append((char)c);
+        }
+
+        if (c < 0)
+        {
+            return null;
+        }
+
+        return l.toString();
+    }
+
+    private Certificate readDERCertificate(
+        ASN1InputStream dIn)
+        throws IOException
+    {
+        ASN1Sequence    seq = (ASN1Sequence)dIn.readObject();
+
+        if (seq.size() > 1
+                && seq.getObjectAt(0) instanceof DERObjectIdentifier)
+        {
+            if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData))
+            {
+                sData = new SignedData(ASN1Sequence.getInstance(
+                                (ASN1TaggedObject)seq.getObjectAt(1), true));
+
+                return new X509CertificateObject(
+                            X509CertificateStructure.getInstance(
+                                    sData.getCertificates().getObjectAt(sDataObjectCount++)));
+            }
+        }
+
+        return new X509CertificateObject(
+                            X509CertificateStructure.getInstance(seq));
+    }
+
+    /**
+     * read in a BER encoded PKCS7 certificate.
+     */
+    private Certificate readPKCS7Certificate(
+        InputStream  in)
+        throws IOException
+    {
+        ASN1InputStream  dIn = new ASN1InputStream(in, getLimit(in));
+        ASN1Sequence     seq = (ASN1Sequence)dIn.readObject();
+
+        if (seq.size() > 1
+                && seq.getObjectAt(0) instanceof DERObjectIdentifier)
+        {
+            if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData))
+            {
+                sData = new SignedData(ASN1Sequence.getInstance(
+                                (ASN1TaggedObject)seq.getObjectAt(1), true));
+    
+                return new X509CertificateObject(
+                            X509CertificateStructure.getInstance(
+                                    sData.getCertificates().getObjectAt(sDataObjectCount++)));
+            }
+        }
+
+        return new X509CertificateObject(
+                     X509CertificateStructure.getInstance(seq));
+    }
+
+    private Certificate readPEMCertificate(
+        InputStream  in)
+        throws IOException
+    {
+        String          line;
+        StringBuffer    pemBuf = new StringBuffer();
+
+        while ((line = readLine(in)) != null)
+        {
+            if (line.equals("-----BEGIN CERTIFICATE-----")
+                || line.equals("-----BEGIN X509 CERTIFICATE-----"))
+            {
+                break;
+            }
+        }
+
+        while ((line = readLine(in)) != null)
+        {
+            if (line.equals("-----END CERTIFICATE-----")
+                || line.equals("-----END X509 CERTIFICATE-----"))
+            {
+                break;
+            }
+
+            pemBuf.append(line);
+        }
+
+        if (pemBuf.length() != 0)
+        {
+            return readDERCertificate(new ASN1InputStream(Base64.decode(pemBuf.toString())));
+        }
+
+        return null;
+    }
+
+    private CRL readDERCRL(
+        ASN1InputStream dIn)
+        throws IOException, CRLException
+    {
+        return new X509CRLObject(new CertificateList((ASN1Sequence)dIn.readObject()));
+    }
+
+    private CRL readPEMCRL(
+        InputStream  in)
+        throws IOException, CRLException
+    {
+        String          line;
+        StringBuffer    pemBuf = new StringBuffer();
+
+        while ((line = readLine(in)) != null)
+        {
+            if (line.equals("-----BEGIN CRL-----")
+                || line.equals("-----BEGIN X509 CRL-----"))
+            {
+                break;
+            }
+        }
+
+        while ((line = readLine(in)) != null)
+        {
+            if (line.equals("-----END CRL-----")
+                || line.equals("-----END X509 CRL-----"))
+            {
+                break;
+            }
+
+            pemBuf.append(line);
+        }
+
+        if (pemBuf.length() != 0)
+        {
+            return readDERCRL(new ASN1InputStream(Base64.decode(pemBuf.toString())));
+        }
+
+        return null;
+    }
+
+    private CRL readPKCS7CRL(
+        InputStream  in)
+        throws IOException, CRLException
+    {
+        ASN1InputStream  dIn = new ASN1InputStream(in, getLimit(in));
+        ASN1Sequence     seq = (ASN1Sequence)dIn.readObject();
+
+        if (seq.size() > 1
+                && seq.getObjectAt(0) instanceof DERObjectIdentifier)
+        {
+            if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData))
+            {
+                sCrlData = new SignedData(ASN1Sequence.getInstance(
+                                (ASN1TaggedObject)seq.getObjectAt(1), true));
+    
+                return new X509CRLObject(
+                            CertificateList.getInstance(
+                                    sCrlData.getCRLs().getObjectAt(sCrlDataObjectCount++)));
+            }
+        }
+
+        return new X509CRLObject(
+                     CertificateList.getInstance(seq));
+    }
+
+    /**
+     * Generates a certificate object and initializes it with the data
+     * read from the input stream inStream.
+     */
+    public Certificate engineGenerateCertificate(
+        InputStream in) 
+        throws CertificateException
+    {
+        if (currentStream == null)
+        {
+            currentStream = in;
+            sData = null;
+            sDataObjectCount = 0;
+        }
+        else if (currentStream != in) // reset if input stream has changed
+        {
+            currentStream = in;
+            sData = null;
+            sDataObjectCount = 0;
+        }
+
+        try
+        {
+            if (sData != null)
+            {
+                if (sDataObjectCount != sData.getCertificates().size())
+                {
+                    return new X509CertificateObject(
+                                X509CertificateStructure.getInstance(
+                                        sData.getCertificates().getObjectAt(sDataObjectCount++)));
+                }
+                else
+                {
+                    sData = null;
+                    sDataObjectCount = 0;
+                    return null;
+                }
+            }
+            
+            if (!in.markSupported())
+            {
+                // BEGIN android-modified
+                in = new BufferedInputStream(in, 8192);
+                // END android-modified
+            }
+            
+            in.mark(10);
+            int    tag = in.read();
+            
+            if (tag == -1)
+            {
+                return null;
+            }
+            
+            if (tag != 0x30)  // assume ascii PEM encoded.
+            {
+                in.reset();
+                return readPEMCertificate(in);
+            }
+            else if (in.read() == 0x80)    // assume BER encoded.
+            {
+                in.reset();
+                return readPKCS7Certificate(new ASN1InputStream(in, getLimit(in)));
+            }
+            else
+            {
+                in.reset();
+                return readDERCertificate(new ASN1InputStream(in, getLimit(in)));
+            }
+        }
+        catch (Exception e)
+        {
+            throw new CertificateException(e.toString());
+        }
+    }
+
+    /**
+     * Returns a (possibly empty) collection view of the certificates
+     * read from the given input stream inStream.
+     */
+    public Collection engineGenerateCertificates(
+        InputStream inStream) 
+        throws CertificateException
+    {
+        Certificate     cert;
+        List            certs = new ArrayList();
+
+        while ((cert = engineGenerateCertificate(inStream)) != null)
+        {
+            certs.add(cert);
+        }
+
+        return certs;
+    }
+
+    /**
+     * Generates a certificate revocation list (CRL) object and initializes
+     * it with the data read from the input stream inStream.
+     */
+    public CRL engineGenerateCRL(
+        InputStream inStream) 
+        throws CRLException
+    {
+        if (currentCrlStream == null)
+        {
+            currentCrlStream = inStream;
+            sCrlData = null;
+            sCrlDataObjectCount = 0;
+        }
+        else if (currentCrlStream != inStream) // reset if input stream has changed
+        {
+            currentCrlStream = inStream;
+            sCrlData = null;
+            sCrlDataObjectCount = 0;
+        }
+
+        try
+        {
+            if (sCrlData != null)
+            {
+                if (sCrlDataObjectCount != sCrlData.getCertificates().size())
+                {
+                    return new X509CRLObject(
+                                CertificateList.getInstance(
+                                        sCrlData.getCRLs().getObjectAt(sCrlDataObjectCount++)));
+                }
+                else
+                {
+                    sCrlData = null;
+                    sCrlDataObjectCount = 0;
+                    return null;
+                }
+            }
+            
+            if (!inStream.markSupported())
+            {
+                // BEGIN android-modified
+                inStream = new BufferedInputStream(inStream, 8192);
+                // END android-modified
+            }
+            
+            inStream.mark(10);
+            if (inStream.read() != 0x30)  // assume ascii PEM encoded.
+            {
+                inStream.reset();
+                return readPEMCRL(inStream);
+            }
+            else if (inStream.read() == 0x80)    // assume BER encoded.
+            {
+                inStream.reset();
+                return readPKCS7CRL(inStream);
+            }
+            else
+            {
+                inStream.reset();
+                return readDERCRL(new ASN1InputStream(inStream, getLimit(inStream)));
+            }
+        }
+        catch (CRLException e)
+        {
+            throw e;
+        }
+        catch (Exception e)
+        {
+            throw new CRLException(e.toString());
+        }
+    }
+
+    /**
+     * Returns a (possibly empty) collection view of the CRLs read from
+     * the given input stream inStream.
+     *
+     * The inStream may contain a sequence of DER-encoded CRLs, or
+     * a PKCS#7 CRL set.  This is a PKCS#7 SignedData object, with the
+     * only signficant field being crls.  In particular the signature
+     * and the contents are ignored.
+     */
+    public Collection engineGenerateCRLs(
+        InputStream inStream) 
+        throws CRLException
+    {
+        CRL     crl;
+        List    crls = new ArrayList();
+
+        while ((crl = engineGenerateCRL(inStream)) != null)
+        {
+            crls.add(crl);
+        }
+
+        return crls;
+    }
+
+    public Iterator engineGetCertPathEncodings()
+    {
+        return PKIXCertPath.certPathEncodings.iterator();
+    }
+
+    public CertPath engineGenerateCertPath(
+        InputStream inStream)
+        throws CertificateException
+    {
+        return engineGenerateCertPath(inStream, "PkiPath");
+    }
+
+    public CertPath engineGenerateCertPath(
+        InputStream inStream,
+        String encoding)
+        throws CertificateException
+    {
+        return new PKIXCertPath(inStream, encoding);
+    }
+
+    public CertPath engineGenerateCertPath(
+        List certificates)
+        throws CertificateException
+    {
+        Iterator iter = certificates.iterator();
+        Object obj;
+        while (iter.hasNext())
+        {
+            obj = iter.next();
+            if (obj != null)
+            {
+                if (!(obj instanceof X509Certificate))
+                {
+                    throw new CertificateException("list contains none X509Certificate object while creating CertPath\n" + obj.toString());
+                }
+            }
+        }
+        return new PKIXCertPath(certificates);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/PBE.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/PBE.java
new file mode 100644
index 0000000..414076d
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/PBE.java
@@ -0,0 +1,279 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.PBEParametersGenerator;
+import org.bouncycastle.crypto.digests.MD5Digest;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
+// END android-removed
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.TigerDigest;
+// END android-removed
+import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator;
+import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;
+import org.bouncycastle.crypto.generators.PKCS5S1ParametersGenerator;
+import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
+import org.bouncycastle.crypto.params.DESParameters;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+public interface PBE
+{
+    //
+    // PBE Based encryption constants - by default we do PKCS12 with SHA-1
+    //
+    static final int        MD5         = 0;
+    static final int        SHA1        = 1;
+    static final int        RIPEMD160   = 2;
+    static final int        TIGER       = 3;
+    static final int        SHA256      = 4;
+
+    static final int        PKCS5S1     = 0;
+    static final int        PKCS5S2     = 1;
+    static final int        PKCS12      = 2;
+    static final int        OPENSSL     = 3;
+
+    /**
+     * uses the appropriate mixer to generate the key and IV if neccessary.
+     */
+    static class Util
+    {
+        static private PBEParametersGenerator makePBEGenerator(
+            int                     type,
+            int                     hash)
+        {
+            PBEParametersGenerator  generator;
+    
+            if (type == PKCS5S1)
+            {
+                switch (hash)
+                {
+                case MD5:
+                    generator = new PKCS5S1ParametersGenerator(new MD5Digest());
+                    break;
+                case SHA1:
+                    generator = new PKCS5S1ParametersGenerator(new SHA1Digest());
+                    break;
+                default:
+                    throw new IllegalStateException("PKCS5 scheme 1 only supports only MD5 and SHA1.");
+                }
+            }
+            else if (type == PKCS5S2)
+            {
+                generator = new PKCS5S2ParametersGenerator();
+            }
+            else if (type == PKCS12)
+            {
+                switch (hash)
+                {
+                case MD5:
+                    generator = new PKCS12ParametersGenerator(new MD5Digest());
+                    break;
+                case SHA1:
+                    generator = new PKCS12ParametersGenerator(new SHA1Digest());
+                    break;
+                // BEGIN android-removed
+                // case RIPEMD160:
+                //     generator = new PKCS12ParametersGenerator(new RIPEMD160Digest());
+                //     break;
+                // case TIGER:
+                //     generator = new PKCS12ParametersGenerator(new TigerDigest());
+                //     break;
+                // END android-removed
+                case SHA256:
+                    generator = new PKCS12ParametersGenerator(new SHA256Digest());
+                    break;
+                default:
+                    throw new IllegalStateException("unknown digest scheme for PBE encryption.");
+                }
+            }
+            else
+            {
+                generator = new OpenSSLPBEParametersGenerator();
+            }
+    
+            return generator;
+        }
+
+        /**
+         * construct a key and iv (if neccessary) suitable for use with a 
+         * Cipher.
+         */
+        static CipherParameters makePBEParameters(
+            JCEPBEKey               pbeKey,
+            AlgorithmParameterSpec  spec,
+            String                  targetAlgorithm)
+        {
+            if ((spec == null) || !(spec instanceof PBEParameterSpec))
+            {
+                throw new IllegalArgumentException("Need a PBEParameter spec with a PBE key.");
+            }
+    
+            PBEParameterSpec        pbeParam = (PBEParameterSpec)spec;
+            PBEParametersGenerator  generator = makePBEGenerator(pbeKey.getType(), pbeKey.getDigest());
+            byte[]                  key = pbeKey.getEncoded();
+            CipherParameters        param;
+    
+            if (pbeKey.shouldTryWrongPKCS12())
+            {
+                key = new byte[2];
+            }
+            
+            generator.init(key, pbeParam.getSalt(), pbeParam.getIterationCount());
+
+            if (pbeKey.getIvSize() != 0)
+            {
+                param = generator.generateDerivedParameters(pbeKey.getKeySize(), pbeKey.getIvSize());
+            }
+            else
+            {
+                param = generator.generateDerivedParameters(pbeKey.getKeySize());
+            }
+
+            if (targetAlgorithm.startsWith("DES"))
+            {
+                if (param instanceof ParametersWithIV)
+                {
+                    KeyParameter    kParam = (KeyParameter)((ParametersWithIV)param).getParameters();
+
+                    DESParameters.setOddParity(kParam.getKey());
+                }
+                else
+                {
+                    KeyParameter    kParam = (KeyParameter)param;
+
+                    DESParameters.setOddParity(kParam.getKey());
+                }
+            }
+
+            for (int i = 0; i != key.length; i++)
+            {
+                key[i] = 0;
+            }
+
+            return param;
+        }
+
+        /**
+         * generate a PBE based key suitable for a MAC algorithm, the
+         * key size is chosen according the MAC size, or the hashing algorithm,
+         * whichever is greater.
+         */
+        static CipherParameters makePBEMacParameters(
+            JCEPBEKey               pbeKey,
+            AlgorithmParameterSpec  spec)
+        {
+            if ((spec == null) || !(spec instanceof PBEParameterSpec))
+            {
+                throw new IllegalArgumentException("Need a PBEParameter spec with a PBE key.");
+            }
+    
+            PBEParameterSpec        pbeParam = (PBEParameterSpec)spec;
+            PBEParametersGenerator  generator = makePBEGenerator(pbeKey.getType(), pbeKey.getDigest());
+            byte[]                  key = pbeKey.getEncoded();
+            CipherParameters        param;
+    
+            if (pbeKey.shouldTryWrongPKCS12())
+            {
+                key = new byte[2];
+            }
+            
+            generator.init(key, pbeParam.getSalt(), pbeParam.getIterationCount());
+
+            param = generator.generateDerivedMacParameters(pbeKey.getKeySize());
+    
+            for (int i = 0; i != key.length; i++)
+            {
+                key[i] = 0;
+            }
+
+            return param;
+        }
+    
+        /**
+         * construct a key and iv (if neccessary) suitable for use with a 
+         * Cipher.
+         */
+        static CipherParameters makePBEParameters(
+            PBEKeySpec              keySpec,
+            int                     type,
+            int                     hash,
+            int                     keySize,
+            int                     ivSize)
+        {    
+            PBEParametersGenerator  generator = makePBEGenerator(type, hash);
+            byte[]                  key;
+            CipherParameters        param;
+    
+            if (type == PKCS12)
+            {
+                key = PBEParametersGenerator.PKCS12PasswordToBytes(keySpec.getPassword());
+            }
+            else
+            {   
+                key = PBEParametersGenerator.PKCS5PasswordToBytes(keySpec.getPassword());
+            }
+            
+            generator.init(key, keySpec.getSalt(), keySpec.getIterationCount());
+    
+            if (ivSize != 0)
+            {
+                param = generator.generateDerivedParameters(keySize, ivSize);
+            }
+            else
+            {
+                param = generator.generateDerivedParameters(keySize);
+            }
+    
+            for (int i = 0; i != key.length; i++)
+            {
+                key[i] = 0;
+            }
+    
+            return param;
+        }
+    
+        /**
+         * generate a PBE based key suitable for a MAC algorithm, the
+         * key size is chosen according the MAC size, or the hashing algorithm,
+         * whichever is greater.
+         */
+        static CipherParameters makePBEMacParameters(
+            PBEKeySpec              keySpec,
+            int                     type,
+            int                     hash,
+            int                     keySize)
+        {
+            PBEParametersGenerator  generator = makePBEGenerator(type, hash);
+            byte[]                  key;
+            CipherParameters        param;
+    
+            if (type == PKCS12)
+            {
+                key = PBEParametersGenerator.PKCS12PasswordToBytes(keySpec.getPassword());
+            }
+            else
+            {   
+                key = PBEParametersGenerator.PKCS5PasswordToBytes(keySpec.getPassword());
+            }
+            
+            generator.init(key, keySpec.getSalt(), keySpec.getIterationCount());
+    
+            param = generator.generateDerivedMacParameters(keySize);
+    
+            for (int i = 0; i != key.length; i++)
+            {
+                key[i] = 0;
+            }
+    
+            return param;
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/PKIXCertPath.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/PKIXCertPath.java
new file mode 100644
index 0000000..25053c3
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/PKIXCertPath.java
@@ -0,0 +1,393 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.security.NoSuchProviderException;
+import java.security.cert.CertPath;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERSet;
+import org.bouncycastle.asn1.pkcs.ContentInfo;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.SignedData;
+// BEGIN android-removed
+// import org.bouncycastle.openssl.PEMWriter;
+// END android-removed
+
+/**
+ * CertPath implementation for X.509 certificates.
+ * <br />
+ **/
+public  class PKIXCertPath
+    extends CertPath
+{
+    static final List certPathEncodings;
+
+    static
+    {
+        List encodings = new ArrayList();
+        encodings.add("PkiPath");
+        encodings.add("PEM");
+        encodings.add("PKCS7");
+        certPathEncodings = Collections.unmodifiableList(encodings);
+    }
+
+    private List certificates;
+
+    /**
+     * @param certs
+     */
+    private List sortCerts(
+        List certs)
+    {
+        if (certs.size() < 2)
+        {
+            return certs;
+        }
+        
+        X500Principal   issuer = ((X509Certificate)certs.get(0)).getIssuerX500Principal();
+        boolean         okay = true;
+        
+        for (int i = 1; i != certs.size(); i++) 
+        {
+            X509Certificate cert = (X509Certificate)certs.get(i);
+            
+            if (issuer.equals(cert.getSubjectX500Principal()))
+            {
+                issuer = ((X509Certificate)certs.get(i)).getIssuerX500Principal();
+            }
+            else
+            {
+                okay = false;
+                break;
+            }
+        }
+        
+        if (okay)
+        {
+            return certs;
+        }
+        
+        // find end-entity cert
+        List       retList = new ArrayList(certs.size());
+        
+        for (int i = 0; i < certs.size(); i++)
+        {
+            X509Certificate cert = (X509Certificate)certs.get(i);
+            boolean         found = false;
+            
+            X500Principal   subject = cert.getSubjectX500Principal();
+            
+            for (int j = 0; j != certs.size(); j++)
+            {
+                X509Certificate c = (X509Certificate)certs.get(j);
+                if (c.getIssuerX500Principal().equals(subject))
+                {
+                    found = true;
+                    break;
+                }
+            }
+            
+            if (!found)
+            {
+                retList.add(cert);
+                certs.remove(i);
+            }
+        }
+        
+        // can only have one end entity cert - something's wrong, give up.
+        if (retList.size() > 1)
+        {
+            for (int i = 0; i != certs.size(); i++)
+            {
+                retList.add(certs.get(i));
+            }
+            
+            return retList;
+        }
+
+        for (int i = 0; i != retList.size(); i++)
+        {
+            issuer = ((X509Certificate)retList.get(i)).getIssuerX500Principal();
+            
+            for (int j = 0; j < certs.size(); j++)
+            {
+                X509Certificate c = (X509Certificate)certs.get(j);
+                if (issuer.equals(c.getSubjectX500Principal()))
+                {
+                    retList.add(c);
+                    certs.remove(j);
+                    break;
+                }
+            }
+        }
+        
+        // make sure all certificates are accounted for.
+        for (int i = 0; i != certs.size(); i++)
+        {
+            retList.add(certs.get(i));
+        }
+        
+        return retList;
+    }
+
+    PKIXCertPath(List certificates)
+    {
+        super("X.509");
+        this.certificates = sortCerts(new ArrayList(certificates));
+    }
+
+    /**
+     * Creates a CertPath of the specified type.
+     * This constructor is protected because most users should use
+     * a CertificateFactory to create CertPaths.
+     **/
+    PKIXCertPath(
+        InputStream inStream,
+        String encoding)
+        throws CertificateException
+    {
+        super("X.509");
+        try
+        {
+            if (encoding.equalsIgnoreCase("PkiPath"))
+            {
+                ASN1InputStream derInStream = new ASN1InputStream(inStream);
+                DERObject derObject = derInStream.readObject();
+                if (!(derObject instanceof ASN1Sequence))
+                {
+                    throw new CertificateException("input stream does not contain a ASN1 SEQUENCE while reading PkiPath encoded data to load CertPath");
+                }
+                Enumeration e = ((ASN1Sequence)derObject).getObjects();
+                InputStream certInStream;
+                ByteArrayOutputStream outStream;
+                DEROutputStream derOutStream;
+                certificates = new ArrayList();
+                CertificateFactory certFactory= CertificateFactory.getInstance("X.509", "BC");
+                while (e.hasMoreElements())
+                {
+                    outStream = new ByteArrayOutputStream();
+                    derOutStream = new DEROutputStream(outStream);
+        
+                    derOutStream.writeObject(e.nextElement());
+                    derOutStream.close();
+    
+                    certInStream = new ByteArrayInputStream(outStream.toByteArray());
+                    certificates.add(0,certFactory.generateCertificate(certInStream));
+                }
+            }
+            else if (encoding.equalsIgnoreCase("PKCS7") || encoding.equalsIgnoreCase("PEM"))
+            {
+                // BEGIN android-modified
+                inStream = new BufferedInputStream(inStream, 8192);
+                // END android-modified
+                certificates = new ArrayList();
+                CertificateFactory certFactory= CertificateFactory.getInstance("X.509", "BC");
+                Certificate cert;
+                while ((cert = certFactory.generateCertificate(inStream)) != null)
+                {
+                    certificates.add(cert);
+                }
+            }
+            else
+            {
+                throw new CertificateException("unsupported encoding: " + encoding);
+            }
+        }
+        catch (IOException ex) 
+        {
+            throw new CertificateException("IOException throw while decoding CertPath:\n" + ex.toString()); 
+        }
+        catch (NoSuchProviderException ex) 
+        {
+            throw new CertificateException("BouncyCastle provider not found while trying to get a CertificateFactory:\n" + ex.toString()); 
+        }
+        
+        this.certificates = sortCerts(certificates);
+    }
+    
+    /**
+     * Returns an iteration of the encodings supported by this
+     * certification path, with the default encoding
+     * first. Attempts to modify the returned Iterator via its
+     * remove method result in an UnsupportedOperationException.
+     *
+     * @return an Iterator over the names of the supported encodings (as Strings)
+     **/
+    public Iterator getEncodings()
+    {
+        return certPathEncodings.iterator();
+    }
+
+    /**
+     * Returns the encoded form of this certification path, using
+     * the default encoding.
+     *
+     * @return the encoded bytes
+     * @exception CertificateEncodingException if an encoding error occurs
+     **/
+    public byte[] getEncoded()
+        throws CertificateEncodingException
+    {
+        Iterator iter = getEncodings();
+        if (iter.hasNext())
+        {
+            Object enc = iter.next();
+            if (enc instanceof String)
+            {
+            return getEncoded((String)enc);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the encoded form of this certification path, using
+     * the specified encoding.
+     *
+     * @param encoding the name of the encoding to use
+     * @return the encoded bytes
+     * @exception CertificateEncodingException if an encoding error
+     * occurs or the encoding requested is not supported
+     *
+     **/
+    public byte[] getEncoded(String encoding)
+        throws CertificateEncodingException
+    {
+        if (encoding.equalsIgnoreCase("PkiPath"))
+        {
+            ASN1EncodableVector v = new ASN1EncodableVector();
+
+            ListIterator iter = certificates.listIterator(certificates.size());
+            while (iter.hasPrevious())
+            {
+                v.add(toASN1Object((X509Certificate)iter.previous()));
+            }
+
+            return toDEREncoded(new DERSequence(v));
+        }
+        else if (encoding.equalsIgnoreCase("PKCS7"))
+        {
+            ContentInfo encInfo = new ContentInfo(PKCSObjectIdentifiers.data, null);
+
+            ASN1EncodableVector v = new ASN1EncodableVector();
+            for (int i = 0; i != certificates.size(); i++)
+            {
+                v.add(toASN1Object((X509Certificate)certificates.get(i)));
+            }
+            
+            SignedData  sd = new SignedData(
+                                     new DERInteger(1),
+                                     new DERSet(),
+                                     encInfo, 
+                                     new DERSet(v), 
+                                     null, 
+                                     new DERSet());
+
+            return toDEREncoded(new ContentInfo(
+                    PKCSObjectIdentifiers.signedData, sd));
+        }
+        // BEGIN android-removed
+        // else if (encoding.equalsIgnoreCase("PEM"))
+        // {
+        //     ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+        //     PEMWriter             pWrt = new PEMWriter(new OutputStreamWriter(bOut));
+        //
+        //     try
+        //     {
+        //         for (int i = 0; i != certificates.size(); i++)
+        //         {
+        //             pWrt.writeObject(certificates.get(i));
+        //         }
+        //     
+        //         pWrt.close();
+        //     }
+        //     catch (Exception e)
+        //     {
+        //         throw new CertificateEncodingException("can't encode certificate for PEM encoded path");
+        //     }
+        //
+        //     return bOut.toByteArray();
+        // }
+        // END android-removed
+        else
+        {
+            throw new CertificateEncodingException("unsupported encoding: " + encoding);
+        }
+    }
+
+    /**
+     * Returns the list of certificates in this certification
+     * path. The List returned must be immutable and thread-safe. 
+     *
+     * @return an immutable List of Certificates (may be empty, but not null)
+     **/
+    public List getCertificates()
+    {
+        return Collections.unmodifiableList(new ArrayList(certificates));
+    }
+
+    /**
+     * Return a DERObject containing the encoded certificate.
+     *
+     * @param cert the X509Certificate object to be encoded
+     *
+     * @return the DERObject
+     **/
+    private DERObject toASN1Object(
+        X509Certificate cert)
+        throws CertificateEncodingException
+    {
+        try
+        {
+            return new ASN1InputStream(cert.getEncoded()).readObject();
+        }
+        catch (Exception e)
+        {
+            throw new CertificateEncodingException("Exception while encoding certificate: " + e.toString());
+        }
+    }
+    
+    private byte[] toDEREncoded(ASN1Encodable obj) 
+        throws CertificateEncodingException
+    {
+        try
+        {
+            ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+            DEROutputStream       dOut = new DEROutputStream(bOut);
+            
+            dOut.writeObject(obj);
+            dOut.close();
+            
+            return bOut.toByteArray();
+        }
+        catch (IOException e)
+        {
+            throw new CertificateEncodingException("Exeption thrown: " + e);
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java
new file mode 100644
index 0000000..577e5ca
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java
@@ -0,0 +1,353 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.PublicKey;
+import java.security.cert.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * Implements the PKIX CertPathBuilding algorithem for BouncyCastle.
+ * <br />
+ * <b>MAYBE: implement more CertPath validation whil build path to omit invalid pathes</b>
+ *
+ * @see CertPathBuilderSpi
+ **/
+public class PKIXCertPathBuilderSpi
+    extends CertPathBuilderSpi
+{
+    /**
+     * Build and validate a CertPath using the given parameter.
+     *
+     * @param params PKIXBuilderParameters object containing all
+     * information to build the CertPath
+     **/
+    public CertPathBuilderResult engineBuild(
+        CertPathParameters params)
+        throws CertPathBuilderException, InvalidAlgorithmParameterException 
+    {
+        if (!(params instanceof PKIXBuilderParameters))
+        {
+            throw new InvalidAlgorithmParameterException("params must be a PKIXBuilderParameters instance");
+        }
+
+        PKIXBuilderParameters pkixParams = (PKIXBuilderParameters)params;
+
+        Collection targets;
+        Iterator targetIter;
+        List certPathList = new ArrayList();
+        X509Certificate cert;
+        Collection      certs;
+        CertPath        certPath = null;
+        Exception       certPathException = null;
+
+        // search target certificates
+        CertSelector certSelect = pkixParams.getTargetCertConstraints();
+        if (certSelect == null)
+        {
+            throw new CertPathBuilderException("targetCertConstraints must be non-null for CertPath building");
+        }
+
+        try
+        {
+            targets = findCertificates(certSelect, pkixParams.getCertStores());
+        }
+        catch (CertStoreException e)
+        {
+            throw new CertPathBuilderException(e);
+        }
+
+        if (targets.isEmpty())
+        {
+            throw new CertPathBuilderException("no certificate found matching targetCertContraints");
+        }
+
+        CertificateFactory  cFact;
+        CertPathValidator   validator;
+
+        try
+        {
+            cFact = CertificateFactory.getInstance("X.509", "BC");
+            validator = CertPathValidator.getInstance("PKIX", "BC");
+        }
+        catch (Exception e)
+        {
+            throw new CertPathBuilderException("exception creating support classes: " + e);
+        }
+
+        //
+        // check all potential target certificates
+        targetIter = targets.iterator();
+        while (targetIter.hasNext())
+        {
+            cert = (X509Certificate)targetIter.next();
+            certPathList.clear();
+            while (cert != null)
+            {
+                // add cert to the certpath
+                certPathList.add(cert);
+
+                // check wether the issuer of <cert> is a TrustAnchor 
+                if (findTrustAnchor(cert, pkixParams.getTrustAnchors()) != null)
+                {
+                    try
+                    {
+                        certPath = cFact.generateCertPath(certPathList);
+
+                        PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult)validator.validate(certPath, pkixParams);
+
+                        return new PKIXCertPathBuilderResult(certPath,
+                                     result.getTrustAnchor(),
+                                     result.getPolicyTree(),
+                                     result.getPublicKey());
+                    }
+                    catch (CertificateException ex)
+                    {
+                        certPathException = ex;
+                    }
+                    catch (CertPathValidatorException ex)
+                    {
+                        certPathException = ex;
+                    }
+                    // if validation failed go to next certificate
+                    cert = null;
+                }
+                else
+                {
+                    // try to get the issuer certificate from one
+                    // of the CertStores
+                    try
+                    {
+                        X509Certificate issuer = findIssuer(cert, pkixParams.getCertStores());
+                        if (issuer.equals(cert))
+                        {
+                            cert = null;
+                        }
+                        else
+                        {
+                            cert = issuer;
+                        }
+                    }
+                    catch (CertPathValidatorException ex)
+                    {
+                        certPathException = ex;
+                        cert = null;
+                    }
+                }
+            }
+        }
+
+        if (certPath != null)
+        {
+            throw new CertPathBuilderException("found certificate chain, but could not be validated", certPathException);
+        }
+
+        throw new CertPathBuilderException("unable to find certificate chain");
+    }
+
+    /**
+     * Search the given Set of TrustAnchor's for one that is the
+     * issuer of the fiven X509 certificate.
+     *
+     * @param cert the X509 certificate
+     * @param trustAnchors a Set of TrustAnchor's
+     *
+     * @return the <code>TrustAnchor</code> object if found or
+     * <code>null</code> if not.
+     *
+     * @exception CertPathValidatorException if a TrustAnchor  was
+     * found but the signature verificytion on the given certificate
+     * has thrown an exception. This Exception can be obtainted with
+     * <code>getCause()</code> method.
+     **/
+    final TrustAnchor findTrustAnchor(
+        X509Certificate cert,
+        Set             trustAnchors) 
+        throws CertPathBuilderException
+    {
+        Iterator iter = trustAnchors.iterator();
+        TrustAnchor trust = null;
+        PublicKey trustPublicKey = null;
+        Exception invalidKeyEx = null;
+
+        X509CertSelector certSelectX509 = new X509CertSelector();
+
+        try
+        {
+            certSelectX509.setSubject(cert.getIssuerX500Principal().getEncoded());
+        }
+        catch (IOException ex)
+        {
+            throw new CertPathBuilderException("can't get trust anchor principal",null);
+        }
+
+        while (iter.hasNext() && trust == null)
+        {
+            trust = (TrustAnchor)iter.next();
+            if (trust.getTrustedCert() != null)
+            {
+                if (certSelectX509.match(trust.getTrustedCert()))
+                {
+                    trustPublicKey = trust.getTrustedCert().getPublicKey();
+                }
+                else
+                {
+                    trust = null;
+                }
+            }
+            else if (trust.getCAName() != null
+                        && trust.getCAPublicKey() != null)
+            {
+                try
+                {
+                    X500Principal certIssuer = cert.getIssuerX500Principal();
+                    X500Principal caName = new X500Principal(trust.getCAName());
+                    if (certIssuer.equals(caName))
+                    {
+                        trustPublicKey = trust.getCAPublicKey();
+                    }
+                    else
+                    {
+                        trust = null;
+                    }
+                }
+                catch (IllegalArgumentException ex)
+                {
+                    trust = null;
+                }
+            }
+            else
+            {
+                trust = null;
+            }
+            
+            if (trustPublicKey != null)
+            {
+                try
+                {
+                    cert.verify(trustPublicKey);
+                }
+                catch (Exception ex)
+                {
+                    invalidKeyEx = ex;
+                    trust = null;
+                }
+            }
+        }
+    
+        if (trust == null && invalidKeyEx != null)
+        {
+            throw new CertPathBuilderException("TrustAnchor found put certificate validation failed",invalidKeyEx);
+        }
+
+        return trust;
+    }
+
+    /**
+     * Return a Collection of all certificates found in the
+     * CertStore's that are matching the certSelect criteriums.
+     *
+     * @param certSelector a {@link CertSelector CertSelector}
+     * object that will be used to select the certificates
+     * @param certStores a List containing only {@link CertStore
+     * CertStore} objects. These are used to search for
+     * certificates
+     *
+     * @return a Collection of all found {@link Certificate Certificate}
+     * objects. May be empty but never <code>null</code>.
+     **/
+    private final Collection findCertificates(
+        CertSelector    certSelect,
+        List            certStores) 
+        throws CertStoreException
+    {
+        Set certs = new HashSet();
+        Iterator iter = certStores.iterator();
+
+        while (iter.hasNext())
+        {
+            CertStore   certStore = (CertStore)iter.next();
+
+            certs.addAll(certStore.getCertificates(certSelect));
+        }
+
+        return certs;
+    }
+    
+    /**
+     * Find the issuer certificate of the given certificate.
+     *
+     * @param cert the certificate hows issuer certificate should
+     * be found.
+     * @param certStores a list of <code>CertStore</code> object
+     * that will be searched
+     *
+     * @return then <code>X509Certificate</code> object containing
+     * the issuer certificate or <code>null</code> if not found
+     *
+     * @exception CertPathValidatorException if a TrustAnchor  was
+     * found but the signature verificytion on the given certificate
+     * has thrown an exception. This Exception can be obtainted with
+     * <code>getCause()</code> method.
+     **/
+    private final X509Certificate findIssuer(
+        X509Certificate cert,
+        List certStores)
+        throws CertPathValidatorException
+    {
+        Exception invalidKeyEx = null;
+        X509CertSelector certSelect = new X509CertSelector();
+        try
+        {
+            certSelect.setSubject(cert.getIssuerX500Principal().getEncoded());
+        }
+        catch (IOException ex)
+        {
+            throw new CertPathValidatorException("Issuer not found", null, null, -1);
+        }
+
+        Iterator iter;
+        try
+        {
+            iter = findCertificates(certSelect, certStores).iterator();
+        }
+        catch (CertStoreException e)
+        {
+            throw new CertPathValidatorException(e);
+        }
+        
+        X509Certificate issuer = null;
+        while (iter.hasNext() && issuer == null)
+        {
+            issuer = (X509Certificate)iter.next();
+            try
+            {
+                cert.verify(issuer.getPublicKey());
+            }
+            catch (Exception ex)
+            {
+                invalidKeyEx = ex;
+                issuer = null;
+            }
+        }
+
+        if (issuer == null && invalidKeyEx == null)
+        {
+           throw new CertPathValidatorException("Issuer not found", null, null, -1);
+        }
+
+        if (issuer == null && invalidKeyEx != null)
+        {
+            throw new CertPathValidatorException("issuer found but certificate validation failed",invalidKeyEx,null,-1);
+        }
+
+        return issuer;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java
new file mode 100644
index 0000000..0a2ca51
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java
@@ -0,0 +1,1457 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.PublicKey;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathParameters;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertPathValidatorResult;
+import java.security.cert.CertPathValidatorSpi;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.PKIXCertPathValidatorResult;
+import java.security.cert.PKIXParameters;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509CRLSelector;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DEREnumerated;
+import org.bouncycastle.asn1.DERIA5String;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.BasicConstraints;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.GeneralSubtree;
+import org.bouncycastle.asn1.x509.IssuingDistributionPoint;
+import org.bouncycastle.asn1.x509.NameConstraints;
+import org.bouncycastle.asn1.x509.PolicyInformation;
+import org.bouncycastle.asn1.x509.X509Extensions;
+
+/**
+ * CertPathValidatorSpi implemenation for X.509 Certificate validation ala rfc 3280<br />
+ **/
+public class PKIXCertPathValidatorSpi extends CertPathValidatorSpi
+{
+    private static final String CERTIFICATE_POLICIES = X509Extensions.CertificatePolicies.getId();
+    private static final String POLICY_MAPPINGS = X509Extensions.PolicyMappings.getId();
+    private static final String INHIBIT_ANY_POLICY = X509Extensions.InhibitAnyPolicy.getId();
+    private static final String ISSUING_DISTRIBUTION_POINT = X509Extensions.IssuingDistributionPoint.getId();
+    private static final String DELTA_CRL_INDICATOR = X509Extensions.DeltaCRLIndicator.getId();
+    private static final String POLICY_CONSTRAINTS = X509Extensions.PolicyConstraints.getId();
+    private static final String BASIC_CONSTRAINTS = X509Extensions.BasicConstraints.getId();
+    private static final String SUBJECT_ALTERNATIVE_NAME = X509Extensions.SubjectAlternativeName.getId();
+    private static final String NAME_CONSTRAINTS = X509Extensions.NameConstraints.getId();
+    private static final String KEY_USAGE = X509Extensions.KeyUsage.getId();
+
+    private static final String CRL_NUMBER = X509Extensions.CRLNumber.getId();
+
+    private static final String ANY_POLICY = "2.5.29.32.0";
+
+
+    /*
+     * key usage bits
+     */
+    private static final int    KEY_CERT_SIGN = 5;
+    private static final int    CRL_SIGN = 6;
+
+    private static final String[] crlReasons = new String[] {
+                                        "unspecified",
+                                        "keyCompromise",
+                                        "cACompromise",
+                                        "affiliationChanged",
+                                        "superseded",
+                                        "cessationOfOperation",
+                                        "certificateHold",
+                                        "unknown",
+                                        "removeFromCRL",
+                                        "privilegeWithdrawn",
+                                        "aACompromise" };
+    
+    
+    public CertPathValidatorResult engineValidate(
+        CertPath certPath,
+        CertPathParameters params)
+        throws CertPathValidatorException, InvalidAlgorithmParameterException
+    {
+        if (!(params instanceof PKIXParameters))
+        {
+            throw new InvalidAlgorithmParameterException("params must be a PKIXParameters instance");
+        }
+
+        PKIXParameters paramsPKIX = (PKIXParameters)params;
+        if (paramsPKIX.getTrustAnchors() == null)
+        {
+            throw new InvalidAlgorithmParameterException("trustAnchors is null, this is not allowed for path validation");
+        }
+
+        //
+        // 6.1.1 - inputs
+        //
+
+        //
+        // (a)
+        //
+        List    certs = certPath.getCertificates();
+        int     n = certs.size();
+        
+        if (certs.isEmpty())
+        {
+            throw new CertPathValidatorException("CertPath is empty", null, certPath, 0);
+        }
+
+        //
+        // (b)
+        //
+        Date validDate = CertPathValidatorUtilities.getValidDate(paramsPKIX);
+
+        //
+        // (c)
+        //
+        Set userInitialPolicySet = paramsPKIX.getInitialPolicies();
+
+        //
+        // (d)
+        // 
+        X509Certificate lastCert = (X509Certificate)certs.get(certs.size() - 1);
+        TrustAnchor trust = CertPathValidatorUtilities.findTrustAnchor(lastCert, certPath, certs.size() - 1, paramsPKIX.getTrustAnchors());
+
+        if (trust == null)
+        {
+            throw new CertPathValidatorException("TrustAnchor for CertPath not found.", null, certPath, -1);
+        }
+        
+        //
+        // (e), (f), (g) are part of the paramsPKIX object.
+        //
+
+        Iterator certIter;
+        int index = 0;
+        int i;
+
+        //
+        // 6.1.2 - setup
+        //
+
+        //
+        // (a)
+        //
+        List     []  policyNodes = new ArrayList[n + 1];
+        for (int j = 0; j < policyNodes.length; j++)
+        {
+            policyNodes[j] = new ArrayList();
+        }
+
+        Set policySet = new HashSet();
+
+        policySet.add(ANY_POLICY);
+
+        PKIXPolicyNode  validPolicyTree = new PKIXPolicyNode(new ArrayList(), 0, policySet, null, new HashSet(), ANY_POLICY, false);
+
+        policyNodes[0].add(validPolicyTree);
+
+        //
+        // (b)
+        //
+        Set     permittedSubtreesDN = new HashSet();
+        Set     permittedSubtreesEmail = new HashSet();
+        Set     permittedSubtreesIP = new HashSet();
+    
+        //
+        // (c)
+        //
+        Set     excludedSubtreesDN = new HashSet();
+        Set     excludedSubtreesEmail = new HashSet();
+        Set     excludedSubtreesIP = new HashSet();
+    
+        //
+        // (d)
+        //
+        int explicitPolicy;
+        Set acceptablePolicies = null;
+
+        if (paramsPKIX.isExplicitPolicyRequired())
+        {
+            explicitPolicy = 0;
+        }
+        else
+        {
+            explicitPolicy = n + 1;
+        }
+
+        //
+        // (e)
+        //
+        int inhibitAnyPolicy;
+
+        if (paramsPKIX.isAnyPolicyInhibited())
+        {
+            inhibitAnyPolicy = 0;
+        }
+        else
+        {
+            inhibitAnyPolicy = n + 1;
+        }
+    
+        //
+        // (f)
+        //
+        int policyMapping;
+
+        if (paramsPKIX.isPolicyMappingInhibited())
+        {
+            policyMapping = 0;
+        }
+        else
+        {
+            policyMapping = n + 1;
+        }
+    
+        //
+        // (g), (h), (i), (j)
+        //
+        PublicKey workingPublicKey;
+        X500Principal workingIssuerName;
+
+        X509Certificate sign = trust.getTrustedCert();
+        try
+        {
+            if (sign != null)
+            {
+                workingIssuerName = CertPathValidatorUtilities.getSubjectPrincipal(sign);
+                workingPublicKey = sign.getPublicKey();
+            }
+            else
+            {
+                workingIssuerName = new X500Principal(trust.getCAName());
+                workingPublicKey = trust.getCAPublicKey();
+            }
+        }
+        catch (IllegalArgumentException ex)
+        {
+            throw new CertPathValidatorException("TrustAnchor subjectDN: " + ex.toString());
+        }
+
+        boolean trustAnchorInChain = false;
+        if (workingIssuerName.equals(CertPathValidatorUtilities.getSubjectPrincipal(lastCert)) &&
+            workingPublicKey.equals(lastCert.getPublicKey()))
+        {
+            trustAnchorInChain = true;
+        }
+
+        AlgorithmIdentifier workingAlgId = CertPathValidatorUtilities.getAlgorithmIdentifier(workingPublicKey);
+        DERObjectIdentifier workingPublicKeyAlgorithm = workingAlgId.getObjectId();
+        DEREncodable        workingPublicKeyParameters = workingAlgId.getParameters();
+
+        //
+        // (k)
+        //
+        int maxPathLength = n;
+
+        //
+        // 6.1.3
+        //
+        Iterator tmpIter;
+        int tmpInt;
+
+        if (paramsPKIX.getTargetCertConstraints() != null
+            && !paramsPKIX.getTargetCertConstraints().match((X509Certificate)certs.get(0)))
+        {
+            throw new CertPathValidatorException("target certificate in certpath does not match targetcertconstraints", null, certPath, 0);
+        }
+
+
+        // 
+        // initialise CertPathChecker's
+        //
+        List  pathCheckers = paramsPKIX.getCertPathCheckers();
+        certIter = pathCheckers.iterator();
+        while (certIter.hasNext())
+        {
+            ((PKIXCertPathChecker)certIter.next()).init(false);
+        }
+
+        X509Certificate cert = null;
+
+        for (index = certs.size() - 1; index >= 0 ; index--)
+        {
+            try
+            {
+                //
+                // i as defined in the algorithm description
+                //
+                i = n - index;
+    
+                //
+                // set certificate to be checked in this round
+                // sign and workingPublicKey and workingIssuerName are set
+                // at the end of the for loop and initialied the
+                // first time from the TrustAnchor
+                //
+                cert = (X509Certificate)certs.get(index);
+    
+                //
+                // 6.1.3
+                //
+    
+                //
+                // (a) verify
+                //
+                try
+                {
+                    // (a) (1)
+                    //
+                    cert.verify(workingPublicKey, "BC");
+                }
+                catch (GeneralSecurityException e)
+                {
+                    throw new CertPathValidatorException("Could not validate certificate signature.", e, certPath, index);
+                }
+    
+                try
+                {
+                    // (a) (2)
+                    //
+                    cert.checkValidity(validDate);
+                }
+                catch (CertificateExpiredException e)
+                {
+                    throw new CertPathValidatorException("Could not validate certificate: " + e.getMessage(), e, certPath, index);
+                }
+                catch (CertificateNotYetValidException e)
+                {
+                    throw new CertPathValidatorException("Could not validate certificate: " + e.getMessage(), e, certPath, index);
+                }
+    
+                //
+                // (a) (3)
+                //
+                if (paramsPKIX.isRevocationEnabled())
+                {
+                    checkCRLs(paramsPKIX, cert, validDate, sign, workingPublicKey);
+                }
+    
+                //
+                // (a) (4) name chaining
+                //
+                if (!CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert).equals(workingIssuerName))
+                {
+                    throw new CertPathValidatorException(
+                                "IssuerName(" + CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert) +
+                                ") does not match SubjectName(" + workingIssuerName +
+                                ") of signing certificate", null, certPath, index);
+                }
+    
+                //
+                // (b), (c) permitted and excluded subtree checking.
+                //
+                if (!(CertPathValidatorUtilities.isSelfIssued(cert) && (i < n)))
+                {
+                    X500Principal principal = CertPathValidatorUtilities.getSubjectPrincipal(cert);
+                    ASN1InputStream aIn = new ASN1InputStream(principal.getEncoded());
+                    ASN1Sequence    dns;
+    
+                    try
+                    {
+                        dns = (ASN1Sequence)aIn.readObject();
+                    }
+                    catch (IOException e)
+                    {
+                        throw new CertPathValidatorException("exception extracting subject name when checking subtrees");
+                    }
+    
+                    CertPathValidatorUtilities.checkPermittedDN(permittedSubtreesDN, dns);
+    
+                    CertPathValidatorUtilities.checkExcludedDN(excludedSubtreesDN, dns);
+            
+                    ASN1Sequence   altName = (ASN1Sequence)CertPathValidatorUtilities.getExtensionValue(cert, SUBJECT_ALTERNATIVE_NAME);
+                    if (altName != null)
+                    {
+                        for (int j = 0; j < altName.size(); j++)
+                        {
+                            ASN1TaggedObject o = (ASN1TaggedObject)altName.getObjectAt(j);
+    
+                            switch(o.getTagNo())
+                            {
+                            case 1:
+                                String email = DERIA5String.getInstance(o, true).getString();
+    
+                                CertPathValidatorUtilities.checkPermittedEmail(permittedSubtreesEmail, email);
+                                CertPathValidatorUtilities.checkExcludedEmail(excludedSubtreesEmail, email);
+                                break;
+                            case 4:
+                                ASN1Sequence altDN = ASN1Sequence.getInstance(o, true);
+    
+                                CertPathValidatorUtilities.checkPermittedDN(permittedSubtreesDN, altDN);
+                                CertPathValidatorUtilities.checkExcludedDN(excludedSubtreesDN, altDN);
+                                break;
+                            case 7:
+                                byte[] ip = ASN1OctetString.getInstance(o, true).getOctets();
+    
+                                CertPathValidatorUtilities.checkPermittedIP(permittedSubtreesIP, ip);
+                                CertPathValidatorUtilities.checkExcludedIP(excludedSubtreesIP, ip);
+                            }
+                        }
+                    }
+                }
+    
+                //
+                // (d) policy Information checking against initial policy and
+                // policy mapping
+                //
+                ASN1Sequence   certPolicies = (ASN1Sequence)CertPathValidatorUtilities.getExtensionValue(cert, CERTIFICATE_POLICIES);
+                if (certPolicies != null && validPolicyTree != null)
+                {
+                    //
+                    // (d) (1)
+                    //
+                    Enumeration e = certPolicies.getObjects();
+                    Set         pols = new HashSet();
+                        
+                    while (e.hasMoreElements())
+                    {
+                        PolicyInformation   pInfo = PolicyInformation.getInstance(e.nextElement());
+                        DERObjectIdentifier pOid = pInfo.getPolicyIdentifier();
+                        
+                        pols.add(pOid.getId());
+    
+                        if (!ANY_POLICY.equals(pOid.getId()))
+                        {
+                            Set pq = CertPathValidatorUtilities.getQualifierSet(pInfo.getPolicyQualifiers());
+                            
+                            boolean match = CertPathValidatorUtilities.processCertD1i(i, policyNodes, pOid, pq);
+                            
+                            if (!match)
+                            {
+                                CertPathValidatorUtilities.processCertD1ii(i, policyNodes, pOid, pq);
+                            }
+                        }
+                    }
+    
+                    if (acceptablePolicies == null || acceptablePolicies.contains(ANY_POLICY))
+                    {
+                        acceptablePolicies = pols;
+                    }
+                    else
+                    {
+                        Iterator    it = acceptablePolicies.iterator();
+                        Set         t1 = new HashSet();
+    
+                        while (it.hasNext())
+                        {
+                            Object  o = it.next();
+    
+                            if (pols.contains(o))
+                            {
+                                t1.add(o);
+                            }
+                        }
+    
+                        acceptablePolicies = t1;
+                    }
+    
+                    //
+                    // (d) (2)
+                    //
+                    if ((inhibitAnyPolicy > 0) || ((i < n) && CertPathValidatorUtilities.isSelfIssued(cert)))
+                    {
+                        e = certPolicies.getObjects();
+    
+                        while (e.hasMoreElements())
+                        {
+                            PolicyInformation   pInfo = PolicyInformation.getInstance(e.nextElement());
+    
+                            if (ANY_POLICY.equals(pInfo.getPolicyIdentifier().getId()))
+                            {
+                                Set    _apq   = CertPathValidatorUtilities.getQualifierSet(pInfo.getPolicyQualifiers());
+                                List      _nodes = policyNodes[i - 1];
+                                
+                                for (int k = 0; k < _nodes.size(); k++)
+                                {
+                                    PKIXPolicyNode _node = (PKIXPolicyNode)_nodes.get(k);
+                                    
+                                    Iterator _policySetIter = _node.getExpectedPolicies().iterator();
+                                    while (_policySetIter.hasNext())
+                                    {
+                                        Object _tmp = _policySetIter.next();
+                                        
+                                        String _policy;
+                                        if (_tmp instanceof String)
+                                        {
+                                            _policy = (String)_tmp;
+                                        }
+                                        else if (_tmp instanceof DERObjectIdentifier)
+                                        {
+                                            _policy = ((DERObjectIdentifier)_tmp).getId();
+                                        }
+                                        else
+                                        {
+                                            continue;
+                                        }
+                                        
+                                        boolean  _found        = false;
+                                        Iterator _childrenIter = _node.getChildren();
+    
+                                        while (_childrenIter.hasNext())
+                                        {
+                                            PKIXPolicyNode _child = (PKIXPolicyNode)_childrenIter.next();
+    
+                                            if (_policy.equals(_child.getValidPolicy()))
+                                            {
+                                                _found = true;
+                                            }
+                                        }
+    
+                                        if (!_found)
+                                        {
+                                            Set _newChildExpectedPolicies = new HashSet();
+                                            _newChildExpectedPolicies.add(_policy);
+    
+                                            PKIXPolicyNode _newChild = new PKIXPolicyNode(new ArrayList(),
+                                                                                          i,
+                                                                                          _newChildExpectedPolicies,
+                                                                                          _node,
+                                                                                          _apq,
+                                                                                          _policy,
+                                                                                          false);
+                                            _node.addChild(_newChild);
+                                            policyNodes[i].add(_newChild);
+                                        }
+                                    }
+                                }
+                                break;
+                            }
+                        }
+                    }
+                
+                    //
+                    // (d) (3)
+                    //
+                    for (int j = (i - 1); j >= 0; j--)
+                    {
+                        List      nodes = policyNodes[j];
+                        
+                        for (int k = 0; k < nodes.size(); k++)
+                        {
+                            PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+                            if (!node.hasChildren())
+                            {
+                                validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes, node);
+                                if (validPolicyTree == null)
+                                {
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                
+                    //
+                    // d (4)
+                    //
+                    Set criticalExtensionOids = cert.getCriticalExtensionOIDs();
+                    
+                    if (criticalExtensionOids != null)
+                    {
+                        boolean critical = criticalExtensionOids.contains(CERTIFICATE_POLICIES);
+                    
+                        List      nodes = policyNodes[i];
+                        for (int j = 0; j < nodes.size(); j++)
+                        {
+                            PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(j);
+                            node.setCritical(critical);
+                        }
+                    }
+                }
+    
+                // 
+                // (e)
+                //
+                if (certPolicies == null)
+                {
+                    validPolicyTree = null;
+                }
+    
+                //
+                // (f)
+                //
+                if (explicitPolicy <= 0 && validPolicyTree == null)
+                {
+                    throw new CertPathValidatorException("No valid policy tree found when one expected.");
+                }
+    
+                //
+                // 6.1.4
+                //
+    
+                if (i != n) // if not at the end-entity certificate
+                {
+                    if (cert != null && cert.getVersion() == 1)
+                    {
+                        if (!(i == 1 && trustAnchorInChain)) // if not at the root certificate
+                        {
+                            throw new CertPathValidatorException(
+                                "Version 1 certs can't be used as intermediate certificates");
+                        }
+                    }
+    
+                    //
+                    //
+                    // (a) check the policy mappings
+                    //
+                    DERObject   pm = CertPathValidatorUtilities.getExtensionValue(cert, POLICY_MAPPINGS);
+                    if (pm != null)
+                    {
+                        ASN1Sequence mappings = (ASN1Sequence)pm;
+                    
+                        for (int j = 0; j < mappings.size(); j++)
+                        {
+                            ASN1Sequence    mapping = (ASN1Sequence)mappings.getObjectAt(j);
+    
+                            DERObjectIdentifier issuerDomainPolicy = (DERObjectIdentifier)mapping.getObjectAt(0);
+                            DERObjectIdentifier subjectDomainPolicy = (DERObjectIdentifier)mapping.getObjectAt(1);
+    
+                            if (ANY_POLICY.equals(issuerDomainPolicy.getId()))
+                            {
+                            
+                                throw new CertPathValidatorException("IssuerDomainPolicy is anyPolicy");
+                            }
+                        
+                            if (ANY_POLICY.equals(subjectDomainPolicy.getId()))
+                            {
+                            
+                                throw new CertPathValidatorException("SubjectDomainPolicy is anyPolicy");
+                            }
+                        }
+                    }
+                  
+                    // (b)
+                    //
+                    if (pm != null)
+                    {
+                        ASN1Sequence mappings = (ASN1Sequence)pm;
+                        Map m_idp = new HashMap();
+                        Set s_idp = new HashSet();
+                        
+                        for (int j = 0; j < mappings.size(); j++)
+                        {
+                            ASN1Sequence mapping = (ASN1Sequence)mappings.getObjectAt(j);
+                            String id_p = ((DERObjectIdentifier)mapping.getObjectAt(0)).getId();
+                            String sd_p = ((DERObjectIdentifier)mapping.getObjectAt(1)).getId();
+                            Set tmp;
+                            
+                            if (!m_idp.containsKey(id_p))
+                            {
+                                tmp = new HashSet();
+                                tmp.add(sd_p);
+                                m_idp.put(id_p, tmp);
+                                s_idp.add(id_p);
+                            }
+                            else
+                            {
+                                tmp = (Set)m_idp.get(id_p);
+                                tmp.add(sd_p);
+                            }
+                        }
+    
+                        Iterator it_idp = s_idp.iterator();
+                        while (it_idp.hasNext())
+                        {
+                            String id_p = (String)it_idp.next();
+    
+                            //
+                            // (1)
+                            //
+                            if (policyMapping > 0)
+                            {
+                                boolean idp_found = false;
+                                Iterator nodes_i = policyNodes[i].iterator();
+                                while (nodes_i.hasNext())
+                                {
+                                    PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+                                    if (node.getValidPolicy().equals(id_p))
+                                    {
+                                        idp_found = true;
+                                        node.expectedPolicies = (Set)m_idp.get(id_p);
+                                        break;
+                                    }
+                                }
+    
+                                if (!idp_found)
+                                {
+                                    nodes_i = policyNodes[i].iterator();
+                                    while (nodes_i.hasNext())
+                                    {
+                                        PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+                                        if (ANY_POLICY.equals(node.getValidPolicy()))
+                                        {
+                                            Set pq = null;
+                                            ASN1Sequence policies = (ASN1Sequence)CertPathValidatorUtilities.getExtensionValue(
+                                                    cert, CERTIFICATE_POLICIES);
+                                            Enumeration e = policies.getObjects();
+                                            while (e.hasMoreElements())
+                                            {
+                                                PolicyInformation pinfo = PolicyInformation.getInstance(e.nextElement());
+                                                if (ANY_POLICY.equals(pinfo.getPolicyIdentifier().getId()))
+                                                {
+                                                    pq = CertPathValidatorUtilities.getQualifierSet(pinfo.getPolicyQualifiers());
+                                                    break;
+                                                }
+                                            }
+                                            boolean ci = false;
+                                            if (cert.getCriticalExtensionOIDs() != null)
+                                            {
+                                                ci = cert.getCriticalExtensionOIDs().contains(CERTIFICATE_POLICIES);
+                                            }
+    
+                                            PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+                                            if (ANY_POLICY.equals(p_node.getValidPolicy()))
+                                            {
+                                                PKIXPolicyNode c_node = new PKIXPolicyNode(
+                                                        new ArrayList(), i,
+                                                        (Set)m_idp.get(id_p),
+                                                        p_node, pq, id_p, ci);
+                                                p_node.addChild(c_node);
+                                                policyNodes[i].add(c_node);
+                                            }
+                                            break;
+                                        }
+                                    }
+                                }
+    
+                            //
+                            // (2)
+                            //
+                            }
+                            else if (policyMapping <= 0)
+                            {
+                                Iterator nodes_i = policyNodes[i].iterator();
+                                while (nodes_i.hasNext())
+                                {
+                                    PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+                                    if (node.getValidPolicy().equals(id_p))
+                                    {
+                                        PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+                                        p_node.removeChild(node);
+                                        nodes_i.remove();
+                                        for (int k = (i - 1); k >= 0; k--)
+                                        {
+                                            List nodes = policyNodes[k];
+                                            for (int l = 0; l < nodes.size(); l++)
+                                            {
+                                                PKIXPolicyNode node2 = (PKIXPolicyNode)nodes.get(l);
+                                                if (!node2.hasChildren())
+                                                {
+                                                    validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes, node2);
+                                                    if (validPolicyTree == null)
+                                                    {
+                                                        break;
+                                                    }
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    
+                    //
+                    // (g) handle the name constraints extension
+                    //
+                    ASN1Sequence ncSeq = (ASN1Sequence)CertPathValidatorUtilities.getExtensionValue(cert, NAME_CONSTRAINTS);
+                    if (ncSeq != null)
+                    {
+                        NameConstraints nc = new NameConstraints(ncSeq);
+    
+                        //
+                        // (g) (1) permitted subtrees
+                        //
+                        ASN1Sequence permitted = nc.getPermittedSubtrees();
+                        if (permitted != null)
+                        {
+                            Enumeration e = permitted.getObjects();
+                            while (e.hasMoreElements())
+                            {
+                                GeneralSubtree  subtree = GeneralSubtree.getInstance(e.nextElement());
+                                GeneralName     base = subtree.getBase();
+    
+                                switch(base.getTagNo())
+                                {
+                                    case 1:
+                                        permittedSubtreesEmail = CertPathValidatorUtilities.intersectEmail(permittedSubtreesEmail, DERIA5String.getInstance(base.getName()).getString());
+                                        break;
+                                    case 4:
+                                        permittedSubtreesDN = CertPathValidatorUtilities.intersectDN(permittedSubtreesDN, (ASN1Sequence)base.getName());
+                                        break;
+                                    case 7:
+                                        permittedSubtreesIP = CertPathValidatorUtilities.intersectIP(permittedSubtreesIP, ASN1OctetString.getInstance(base.getName()).getOctets());
+                                        break;
+                                }
+                            }
+                        }
+                    
+                        //
+                        // (g) (2) excluded subtrees
+                        //
+                        ASN1Sequence excluded = nc.getExcludedSubtrees();
+                        if (excluded != null)
+                        {
+                            Enumeration e = excluded.getObjects();
+                            while (e.hasMoreElements())
+                            {
+                                GeneralSubtree  subtree = GeneralSubtree.getInstance(e.nextElement());
+                                GeneralName     base = subtree.getBase();
+    
+                                switch(base.getTagNo())
+                                {
+                                case 1:
+                                    excludedSubtreesEmail = CertPathValidatorUtilities.unionEmail(excludedSubtreesEmail, DERIA5String.getInstance(base.getName()).getString());
+                                    break;
+                                case 4:
+                                    excludedSubtreesDN = CertPathValidatorUtilities.unionDN(excludedSubtreesDN, (ASN1Sequence)base.getName());
+                                    break;
+                                case 7:
+                                    excludedSubtreesIP = CertPathValidatorUtilities.unionIP(excludedSubtreesIP, ASN1OctetString.getInstance(base.getName()).getOctets());
+                                    break;
+                                }
+                            }
+                        }
+                    }
+    
+                    //
+                    // (h)
+                    //
+                    if (!CertPathValidatorUtilities.isSelfIssued(cert))
+                    {
+                        //
+                        // (1)
+                        //
+                        if (explicitPolicy != 0)
+                        {
+                            explicitPolicy--;
+                        }
+                    
+                        //
+                        // (2)
+                        //
+                        if (policyMapping != 0)
+                        {
+                            policyMapping--;
+                        }
+                    
+                        //
+                        // (3)
+                        //
+                        if (inhibitAnyPolicy != 0)
+                        {
+                            inhibitAnyPolicy--;
+                        }
+                    }
+            
+                    //
+                    // (i)
+                    //
+                    ASN1Sequence pc = (ASN1Sequence)CertPathValidatorUtilities.getExtensionValue(cert, POLICY_CONSTRAINTS);
+                
+                    if (pc != null)
+                    {
+                        Enumeration policyConstraints = pc.getObjects();
+    
+                        while (policyConstraints.hasMoreElements())
+                        {
+                            ASN1TaggedObject    constraint = (ASN1TaggedObject)policyConstraints.nextElement();
+                            switch (constraint.getTagNo())
+                            {
+                            case 0:
+                                tmpInt = DERInteger.getInstance(constraint).getValue().intValue();
+                                if (tmpInt < explicitPolicy)
+                                {
+                                    explicitPolicy = tmpInt;
+                                }
+                                break;
+                            case 1:
+                                tmpInt = DERInteger.getInstance(constraint).getValue().intValue();
+                                if (tmpInt < policyMapping)
+                                {
+                                    policyMapping = tmpInt;
+                                }
+                            break;
+                            }
+                        }
+                    }
+            
+                    //
+                    // (j)
+                    //
+                    DERInteger iap = (DERInteger)CertPathValidatorUtilities.getExtensionValue(cert, INHIBIT_ANY_POLICY);
+                
+                    if (iap != null)
+                    {
+                        int _inhibitAnyPolicy = iap.getValue().intValue();
+                    
+                        if (_inhibitAnyPolicy < inhibitAnyPolicy)
+                        {
+                            inhibitAnyPolicy = _inhibitAnyPolicy;
+                        }
+                    }
+            
+                    //
+                    // (k)
+                    //
+                    BasicConstraints    bc = BasicConstraints.getInstance(
+                            CertPathValidatorUtilities.getExtensionValue(cert, BASIC_CONSTRAINTS));
+                    if (bc != null)
+                    {
+                        if (!(bc.isCA()))
+                        {
+                            throw new CertPathValidatorException("Not a CA certificate");
+                        }
+                    }
+                    else
+                    {
+                        if (!(i == 1 && trustAnchorInChain)) // if not at the root certificate
+                        {
+                            throw new CertPathValidatorException("Intermediate certificate lacks BasicConstraints");
+                        }
+                    }
+                
+                    //
+                    // (l)
+                    //
+                    if (!CertPathValidatorUtilities.isSelfIssued(cert))
+                    {
+                        if (maxPathLength <= 0)
+                        {
+                            throw new CertPathValidatorException("Max path length not greater than zero");
+                        }
+                    
+                        maxPathLength--;
+                    }
+            
+                    //
+                    // (m)
+                    //
+                    if (bc != null)
+                    {
+                        BigInteger          _pathLengthConstraint = bc.getPathLenConstraint();
+                
+                        if (_pathLengthConstraint != null)
+                        {
+                            int _plc = _pathLengthConstraint.intValue();
+    
+                            if (_plc < maxPathLength)
+                            {
+                                maxPathLength = _plc;
+                            }
+                        }
+                    }
+            
+                    //
+                    // (n)
+                    //
+                    boolean[] _usage = cert.getKeyUsage();
+                
+                    if ((_usage != null) && !_usage[5])
+                    {
+                        throw new CertPathValidatorException(
+                                    "Issuer certificate keyusage extension is critical an does not permit key signing.\n",
+                                    null, certPath, index);
+                    }
+    
+                    //
+                    // (o)
+                    //
+                    if (cert.getCriticalExtensionOIDs() != null)
+                    {
+                        Set criticalExtensions = new HashSet(cert.getCriticalExtensionOIDs());
+                        // these extensions are handle by the algorithem
+                        criticalExtensions.remove(KEY_USAGE);
+                        criticalExtensions.remove(CERTIFICATE_POLICIES);
+                        criticalExtensions.remove(POLICY_MAPPINGS);
+                        criticalExtensions.remove(INHIBIT_ANY_POLICY);
+                        criticalExtensions.remove(ISSUING_DISTRIBUTION_POINT);
+                        criticalExtensions.remove(DELTA_CRL_INDICATOR);
+                        criticalExtensions.remove(POLICY_CONSTRAINTS);
+                        criticalExtensions.remove(BASIC_CONSTRAINTS);
+                        criticalExtensions.remove(SUBJECT_ALTERNATIVE_NAME);
+                        criticalExtensions.remove(NAME_CONSTRAINTS);
+    
+                        tmpIter = pathCheckers.iterator();
+                        while (tmpIter.hasNext())
+                        {
+                            try
+                            {
+                                ((PKIXCertPathChecker)tmpIter.next()).check(cert, criticalExtensions);
+                            }
+                            catch (CertPathValidatorException e)
+                            {
+                                throw new CertPathValidatorException(e.getMessage(), e.getCause(), certPath, index);
+                            }
+                        }
+                        if (!criticalExtensions.isEmpty())
+                        {
+                            throw new CertPathValidatorException(
+                                "Certificate has unsupported critical extension", null, certPath, index);
+                        }
+                    }
+                }
+    
+                // set signing certificate for next round
+                sign = cert;
+                workingPublicKey = sign.getPublicKey();
+                try
+                {
+                    workingIssuerName = CertPathValidatorUtilities.getSubjectPrincipal(sign);
+                }
+                catch (IllegalArgumentException ex)
+                {
+                    throw new CertPathValidatorException(sign.getSubjectDN().getName() + " :" + ex.toString());
+                }
+                workingAlgId = CertPathValidatorUtilities.getAlgorithmIdentifier(workingPublicKey);
+                workingPublicKeyAlgorithm = workingAlgId.getObjectId();
+                workingPublicKeyParameters = workingAlgId.getParameters();
+            }
+            catch (AnnotatedException e)
+            {
+                throw new CertPathValidatorException(e.getMessage(), e.getUnderlyingException(), certPath, index);
+            }
+        }
+
+        //
+        // 6.1.5 Wrap-up procedure
+        //
+
+        //
+        // (a)
+        //
+        if (!CertPathValidatorUtilities.isSelfIssued(cert) && (explicitPolicy != 0))
+        {
+            explicitPolicy--;
+        }
+    
+        //
+        // (b)
+        //
+        try
+        {
+            ASN1Sequence pc = (ASN1Sequence)CertPathValidatorUtilities.getExtensionValue(cert, POLICY_CONSTRAINTS);
+            if (pc != null)
+            {
+                Enumeration policyConstraints = pc.getObjects();
+    
+                while (policyConstraints.hasMoreElements())
+                {
+                    ASN1TaggedObject    constraint = (ASN1TaggedObject)policyConstraints.nextElement();
+                    switch (constraint.getTagNo())
+                    {
+                    case 0:
+                        tmpInt = DERInteger.getInstance(constraint).getValue().intValue();
+                        if (tmpInt == 0)
+                        {
+                            explicitPolicy = 0;
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+        catch (AnnotatedException e)
+        {
+            throw new CertPathValidatorException(e.getMessage(), e.getUnderlyingException(), certPath, index);
+        }
+    
+        //
+        // (c) (d) and (e) are already done
+        //
+    
+        //
+        // (f) 
+        //
+        Set criticalExtensions = cert.getCriticalExtensionOIDs();
+        
+        if (criticalExtensions != null)
+        {
+            criticalExtensions = new HashSet(criticalExtensions);
+            // these extensions are handle by the algorithm
+            criticalExtensions.remove(KEY_USAGE);
+            criticalExtensions.remove(CERTIFICATE_POLICIES);
+            criticalExtensions.remove(POLICY_MAPPINGS);
+            criticalExtensions.remove(INHIBIT_ANY_POLICY);
+            criticalExtensions.remove(ISSUING_DISTRIBUTION_POINT);
+            criticalExtensions.remove(DELTA_CRL_INDICATOR);
+            criticalExtensions.remove(POLICY_CONSTRAINTS);
+            criticalExtensions.remove(BASIC_CONSTRAINTS);
+            criticalExtensions.remove(SUBJECT_ALTERNATIVE_NAME);
+            criticalExtensions.remove(NAME_CONSTRAINTS);
+        }
+        else
+        {
+            criticalExtensions = new HashSet();
+        }
+        
+        tmpIter = pathCheckers.iterator();
+        while (tmpIter.hasNext())
+        {
+            try
+            {
+                ((PKIXCertPathChecker)tmpIter.next()).check(cert, criticalExtensions);
+            }
+            catch (CertPathValidatorException e)
+            {
+                throw new CertPathValidatorException(e.getMessage(), e.getCause(), certPath, index);
+            }
+        }
+        
+        if (!criticalExtensions.isEmpty())
+        {
+            throw new CertPathValidatorException(
+                "Certificate has unsupported critical extension", null, certPath, index);
+        }
+
+        //
+        // (g)
+        //
+        PKIXPolicyNode intersection;
+        
+
+        //
+        // (g) (i)
+        //
+        if (validPolicyTree == null)
+        { 
+            if (paramsPKIX.isExplicitPolicyRequired())
+            {
+                throw new CertPathValidatorException("Explicit policy requested but none available.");
+            }
+            intersection = null;
+        }
+        else if (CertPathValidatorUtilities.isAnyPolicy(userInitialPolicySet)) // (g) (ii)
+        {
+            if (paramsPKIX.isExplicitPolicyRequired())
+            {
+                if (acceptablePolicies.isEmpty())
+                {
+                    throw new CertPathValidatorException("Explicit policy requested but none available.");
+                }
+                else
+                {
+                    Set _validPolicyNodeSet = new HashSet();
+                    
+                    for (int j = 0; j < policyNodes.length; j++)
+                    {
+                        List      _nodeDepth = policyNodes[j];
+                        
+                        for (int k = 0; k < _nodeDepth.size(); k++)
+                        {
+                            PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k);
+                            
+                            if (ANY_POLICY.equals(_node.getValidPolicy()))
+                            {
+                                Iterator _iter = _node.getChildren();
+                                while (_iter.hasNext())
+                                {
+                                    _validPolicyNodeSet.add(_iter.next());
+                                }
+                            }
+                        }
+                    }
+                    
+                    Iterator _vpnsIter = _validPolicyNodeSet.iterator();
+                    while (_vpnsIter.hasNext())
+                    {
+                        PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next();
+                        String _validPolicy = _node.getValidPolicy();
+                        
+                        if (!acceptablePolicies.contains(_validPolicy))
+                        {
+                            //validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, _node);
+                        }
+                    }
+                    if (validPolicyTree != null)
+                    {
+                        for (int j = (n - 1); j >= 0; j--)
+                        {
+                            List      nodes = policyNodes[j];
+                            
+                            for (int k = 0; k < nodes.size(); k++)
+                            {
+                                PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+                                if (!node.hasChildren())
+                                {
+                                    validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes, node);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+            intersection = validPolicyTree;
+        }
+        else
+        {
+            //
+            // (g) (iii)
+            //
+            // This implementation is not exactly same as the one described in RFC3280.
+            // However, as far as the validation result is concerned, both produce 
+            // adequate result. The only difference is whether AnyPolicy is remain 
+            // in the policy tree or not. 
+            //
+            // (g) (iii) 1
+            //
+            Set _validPolicyNodeSet = new HashSet();
+            
+            for (int j = 0; j < policyNodes.length; j++)
+            {
+                List      _nodeDepth = policyNodes[j];
+                
+                for (int k = 0; k < _nodeDepth.size(); k++)
+                {
+                    PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k);
+                    
+                    if (ANY_POLICY.equals(_node.getValidPolicy()))
+                    {
+                        Iterator _iter = _node.getChildren();
+                        while (_iter.hasNext())
+                        {
+                            PKIXPolicyNode _c_node = (PKIXPolicyNode)_iter.next();
+                            if (!ANY_POLICY.equals(_c_node.getValidPolicy()))
+                            {
+                                _validPolicyNodeSet.add(_c_node);
+                            }
+                        }
+                    }
+                }
+            }
+            
+            //
+            // (g) (iii) 2
+            //
+            Iterator _vpnsIter = _validPolicyNodeSet.iterator();
+            while (_vpnsIter.hasNext())
+            {
+                PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next();
+                String _validPolicy = _node.getValidPolicy();
+
+                if (!userInitialPolicySet.contains(_validPolicy))
+                {
+                    validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes, _node);
+                }
+            }
+            
+            //
+            // (g) (iii) 4
+            //
+            if (validPolicyTree != null)
+            {
+                for (int j = (n - 1); j >= 0; j--)
+                {
+                    List      nodes = policyNodes[j];
+                    
+                    for (int k = 0; k < nodes.size(); k++)
+                    {
+                        PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+                        if (!node.hasChildren())
+                        {
+                            validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes, node);
+                        }
+                    }
+                }
+            }
+            
+            intersection = validPolicyTree;
+        }
+ 
+        if ((explicitPolicy > 0) || (intersection != null))
+        {
+            return new PKIXCertPathValidatorResult(trust, intersection, workingPublicKey);
+        }
+
+        throw new CertPathValidatorException("Path processing failed on policy.", null, certPath, index);
+    }
+    
+    private void checkCRLs(PKIXParameters paramsPKIX, X509Certificate cert, Date validDate, X509Certificate sign, PublicKey workingPublicKey) 
+        throws AnnotatedException
+    {
+        X509CRLSelector crlselect;
+        crlselect = new X509CRLSelector();
+    
+        try
+        {
+            crlselect.addIssuerName(CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert).getEncoded());
+        }
+        catch (IOException e)
+        {
+            throw new AnnotatedException("Cannot extract issuer from certificate: " + e, e);
+        }
+    
+        crlselect.setCertificateChecking(cert);
+    
+        Iterator crl_iter = CertPathValidatorUtilities.findCRLs(crlselect, paramsPKIX.getCertStores()).iterator();
+        boolean validCrlFound = false;
+        X509CRLEntry crl_entry;
+        while (crl_iter.hasNext())
+        {
+            X509CRL crl = (X509CRL)crl_iter.next();
+    
+            if (cert.getNotAfter().after(crl.getThisUpdate()))
+            {
+                if (crl.getNextUpdate() == null
+                    || validDate.before(crl.getNextUpdate())) 
+                {
+                    validCrlFound = true;
+                }
+    
+                if (sign != null)
+                {
+                    boolean[] keyusage = sign.getKeyUsage();
+    
+                    if (keyusage != null
+                        && (keyusage.length < 7 || !keyusage[CRL_SIGN]))
+                    {
+                        throw new AnnotatedException(
+                            "Issuer certificate keyusage extension does not permit crl signing.\n" + sign);
+                    }
+                }
+    
+                try
+                {
+                    crl.verify(workingPublicKey, "BC");
+                }
+                catch (Exception e)
+                {
+                    throw new AnnotatedException("can't verify CRL: " + e, e);
+                }
+    
+                crl_entry = crl.getRevokedCertificate(cert.getSerialNumber());
+                if (crl_entry != null
+                    && !validDate.before(crl_entry.getRevocationDate()))
+                {
+                    String reason = null;
+                    
+                    if (crl_entry.hasExtensions())
+                    {
+                        DEREnumerated reasonCode = DEREnumerated.getInstance(CertPathValidatorUtilities.getExtensionValue(crl_entry, X509Extensions.ReasonCode.getId()));
+                        if (reasonCode != null)
+                        {
+                            reason = crlReasons[reasonCode.getValue().intValue()];
+                        }
+                    }
+                    
+                    String message = "Certificate revocation after " + crl_entry.getRevocationDate();
+                    
+                    if (reason != null)
+                    {
+                        message += ", reason: " + reason;
+                    }
+                    
+                    throw new AnnotatedException(message);
+                }
+    
+                //
+                // check the DeltaCRL indicator, base point and the issuing distribution point
+                //
+                DERObject idp = CertPathValidatorUtilities.getExtensionValue(crl, ISSUING_DISTRIBUTION_POINT);
+                DERObject dci = CertPathValidatorUtilities.getExtensionValue(crl, DELTA_CRL_INDICATOR);
+    
+                if (dci != null)
+                {
+                    X509CRLSelector baseSelect = new X509CRLSelector();
+    
+                    try
+                    {
+                        baseSelect.addIssuerName(CertPathValidatorUtilities.getIssuerPrincipal(crl).getEncoded());
+                    }
+                    catch (IOException e)
+                    {
+                        throw new AnnotatedException("can't extract issuer from certificate: " + e, e);
+                    }
+    
+                    baseSelect.setMinCRLNumber(((DERInteger)dci).getPositiveValue());
+                    baseSelect.setMaxCRLNumber(((DERInteger)CertPathValidatorUtilities.getExtensionValue(crl, CRL_NUMBER)).getPositiveValue().subtract(BigInteger.valueOf(1)));
+                    
+                    boolean  foundBase = false;
+                    Iterator it  = CertPathValidatorUtilities.findCRLs(baseSelect, paramsPKIX.getCertStores()).iterator();
+                    while (it.hasNext())
+                    {
+                        X509CRL base = (X509CRL)it.next();
+    
+                        DERObject baseIdp = CertPathValidatorUtilities.getExtensionValue(base, ISSUING_DISTRIBUTION_POINT);
+                        
+                        if (idp == null)
+                        {
+                            if (baseIdp == null)
+                            {
+                                foundBase = true;
+                                break;
+                            }
+                        }
+                        else
+                        {
+                            if (idp.equals(baseIdp))
+                            {
+                                foundBase = true;
+                                break;
+                            }
+                        }
+                    }
+                    
+                    if (!foundBase)
+                    {
+                        throw new AnnotatedException("No base CRL for delta CRL");
+                    }
+                }
+    
+                if (idp != null)
+                {
+                    IssuingDistributionPoint    p = IssuingDistributionPoint.getInstance(idp);
+                    BasicConstraints    bc = BasicConstraints.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, BASIC_CONSTRAINTS));
+                    
+                    if (p.onlyContainsUserCerts() && (bc != null && bc.isCA()))
+                    {
+                        throw new AnnotatedException("CA Cert CRL only contains user certificates");
+                    }
+                    
+                    if (p.onlyContainsCACerts() && (bc == null || !bc.isCA()))
+                    {
+                        throw new AnnotatedException("End CRL only contains CA certificates");
+                    }
+                    
+                    if (p.onlyContainsAttributeCerts())
+                    {
+                        throw new AnnotatedException("onlyContainsAttributeCerts boolean is asserted");
+                    }
+                }
+            }
+        }
+    
+        if (!validCrlFound)
+        {
+            throw new AnnotatedException("no valid CRL found");
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/PKIXPolicyNode.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/PKIXPolicyNode.java
new file mode 100644
index 0000000..3437605
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/PKIXPolicyNode.java
@@ -0,0 +1,168 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.cert.PolicyNode;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+public class PKIXPolicyNode
+    implements PolicyNode
+{
+    protected List       children;
+    protected int        depth;
+    protected Set        expectedPolicies;
+    protected PolicyNode parent;
+    protected Set        policyQualifiers;
+    protected String     validPolicy;
+    protected boolean    critical;
+    
+    /*  
+     *  
+     *  CONSTRUCTORS
+     *  
+     */ 
+    
+    public PKIXPolicyNode(
+        List       _children,
+        int        _depth,
+        Set        _expectedPolicies,
+        PolicyNode _parent,
+        Set        _policyQualifiers,
+        String     _validPolicy,
+        boolean    _critical)
+    {
+        children         = _children;
+        depth            = _depth;
+        expectedPolicies = _expectedPolicies;
+        parent           = _parent;
+        policyQualifiers = _policyQualifiers;
+        validPolicy      = _validPolicy;
+        critical         = _critical;
+    }
+    
+    public void addChild(
+        PKIXPolicyNode _child)
+    {
+        children.add(_child);
+        _child.setParent(this);
+    }
+    
+    public Iterator getChildren()
+    {
+        return children.iterator();
+    }
+    
+    public int getDepth()
+    {
+        return depth;
+    }
+    
+    public Set getExpectedPolicies()
+    {
+        return expectedPolicies;
+    }
+    
+    public PolicyNode getParent()
+    {
+        return parent;
+    }
+    
+    public Set getPolicyQualifiers()
+    {
+        return policyQualifiers;
+    }
+    
+    public String getValidPolicy()
+    {
+        return validPolicy;
+    }
+    
+    public boolean hasChildren()
+    {
+        return !children.isEmpty();
+    }
+    
+    public boolean isCritical()
+    {
+        return critical;
+    }
+    
+    public void removeChild(PKIXPolicyNode _child)
+    {
+        children.remove(_child);
+    }
+    
+    public void setCritical(boolean _critical)
+    {
+        critical = _critical;
+    }
+    
+    public void setParent(PKIXPolicyNode _parent)
+    {
+        parent = _parent;
+    }
+    
+    public String toString()
+    {
+        return toString("");
+    }
+    
+    public String toString(String _indent)
+    {
+        StringBuffer _buf = new StringBuffer();
+        _buf.append(_indent);
+        _buf.append(validPolicy);
+        _buf.append(" {\n");
+        
+        for(int i = 0; i < children.size(); i++)
+        {
+            _buf.append(((PKIXPolicyNode)children.get(i)).toString(_indent + "    "));
+        }
+        
+        _buf.append(_indent);
+        _buf.append("}\n");
+        return _buf.toString();
+    }
+    
+    public Object clone()
+    {
+        return copy();
+    }
+    
+    public PKIXPolicyNode copy()
+    {
+        Set     _expectedPolicies = new HashSet();
+        Iterator _iter = expectedPolicies.iterator();
+        while (_iter.hasNext())
+        {
+            _expectedPolicies.add(new String((String)_iter.next()));
+        }
+        
+        Set     _policyQualifiers = new HashSet();
+        _iter = policyQualifiers.iterator();
+        while (_iter.hasNext())
+        {
+            _policyQualifiers.add(new String((String)_iter.next()));
+        }
+        
+        PKIXPolicyNode _node = new PKIXPolicyNode(new ArrayList(),
+                                                  depth,
+                                                  _expectedPolicies,
+                                                  null,
+                                                  _policyQualifiers,
+                                                  new String(validPolicy),
+                                                  critical);
+        
+        _iter = children.iterator();
+        while (_iter.hasNext())
+        {
+            PKIXPolicyNode _child = ((PKIXPolicyNode)_iter.next()).copy();
+            _child.setParent(_node);
+            _node.addChild(_child);
+        }
+        
+        return _node;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/RSAUtil.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/RSAUtil.java
new file mode 100644
index 0000000..0d99117
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/RSAUtil.java
@@ -0,0 +1,53 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+
+/**
+ * utility class for converting java.security RSA objects into their
+ * org.bouncycastle.crypto counterparts.
+ */
+class RSAUtil
+{
+    static boolean isRsaOid(
+        DERObjectIdentifier algOid)
+    {
+        return algOid.equals(PKCSObjectIdentifiers.rsaEncryption)
+            || algOid.equals(X509ObjectIdentifiers.id_ea_rsa)
+            || algOid.equals(PKCSObjectIdentifiers.id_RSASSA_PSS)
+            || algOid.equals(PKCSObjectIdentifiers.id_RSAES_OAEP);
+    }
+    
+    static RSAKeyParameters generatePublicKeyParameter(
+        RSAPublicKey    key)
+    {
+        return new RSAKeyParameters(false, key.getModulus(), key.getPublicExponent());
+
+    }
+
+    static RSAKeyParameters generatePrivateKeyParameter(
+        RSAPrivateKey    key)
+    {
+        if (key instanceof RSAPrivateCrtKey)
+        {
+            RSAPrivateCrtKey    k = (RSAPrivateCrtKey)key;
+
+            return new RSAPrivateCrtKeyParameters(k.getModulus(),
+                k.getPublicExponent(), k.getPrivateExponent(),
+                k.getPrimeP(), k.getPrimeQ(), k.getPrimeExponentP(),                            k.getPrimeExponentQ(), k.getCrtCoefficient());
+        }
+        else
+        {
+            RSAPrivateKey    k = key;
+
+            return new RSAKeyParameters(true, k.getModulus(), k.getPrivateExponent());
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/WrapCipherSpi.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/WrapCipherSpi.java
new file mode 100644
index 0000000..4f14b85
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/WrapCipherSpi.java
@@ -0,0 +1,442 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.CipherSpi;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+import javax.crypto.spec.RC5ParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.Wrapper;
+import org.bouncycastle.crypto.engines.AESWrapEngine;
+import org.bouncycastle.crypto.engines.DESedeWrapEngine;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.engines.RC2WrapEngine;
+// END android-removed
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+public abstract class WrapCipherSpi extends CipherSpi
+    implements PBE
+{
+    //
+    // specs we can handle.
+    //
+    private Class[]                 availableSpecs =
+                                    {
+                                        IvParameterSpec.class,
+                                        PBEParameterSpec.class,
+                                        RC2ParameterSpec.class,
+                                        RC5ParameterSpec.class
+                                    };
+
+    protected int                     pbeType = PKCS12;
+    protected int                     pbeHash = SHA1;
+    protected int                     pbeKeySize;
+    protected int                     pbeIvSize;
+
+    protected AlgorithmParameters     engineParams = null;
+
+    protected Wrapper                   wrapEngine = null;
+
+    protected WrapCipherSpi()
+    {
+    }
+
+    protected WrapCipherSpi(
+        Wrapper wrapEngine)
+    {
+        this.wrapEngine = wrapEngine;
+    }
+
+    protected int engineGetBlockSize()
+    {
+        return 0;
+    }
+
+    protected byte[] engineGetIV()
+    {
+        return null;
+    }
+
+    protected int engineGetKeySize(
+        Key     key)
+    {
+        return key.getEncoded().length;
+    }
+
+    protected int engineGetOutputSize(
+        int     inputLen)
+    {
+        return -1;
+    }
+
+    protected AlgorithmParameters engineGetParameters()
+    {
+        return null;
+    }
+
+    protected void engineSetMode(
+        String  mode)
+        throws NoSuchAlgorithmException
+    {
+        throw new NoSuchAlgorithmException("can't support mode " + mode);
+    }
+
+    protected void engineSetPadding(
+        String  padding)
+    throws NoSuchPaddingException
+    {
+        throw new NoSuchPaddingException("Padding " + padding + " unknown.");
+    }
+
+    protected void engineInit(
+        int                     opmode,
+        Key                     key,
+        AlgorithmParameterSpec  params,
+        SecureRandom            random)
+    throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        CipherParameters        param;
+
+        if (key instanceof JCEPBEKey)
+        {
+            JCEPBEKey   k = (JCEPBEKey)key;
+            
+            if (params instanceof PBEParameterSpec)
+            {
+                param = PBE.Util.makePBEParameters(k, params, wrapEngine.getAlgorithmName());
+            }
+            else if (k.getParam() != null)
+            {
+                param = k.getParam();
+            }
+            else
+            {
+                throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
+            }
+        }
+        else
+        {
+            param = new KeyParameter(key.getEncoded());
+        }
+
+        if (params instanceof javax.crypto.spec.IvParameterSpec)
+        {
+            IvParameterSpec iv = (IvParameterSpec) params;
+            CipherParameters paramPlusIV = new ParametersWithIV(param, iv.getIV());
+            param = paramPlusIV;
+        }
+
+        switch (opmode)
+        {
+        case Cipher.WRAP_MODE:
+            wrapEngine.init(true, param);
+            break;
+        case Cipher.UNWRAP_MODE:
+            wrapEngine.init(false, param);
+            break;
+        case Cipher.ENCRYPT_MODE:
+        case Cipher.DECRYPT_MODE:
+            throw new IllegalArgumentException("engine only valid for wrapping");
+        default:
+            System.out.println("eeek!");
+        }
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key                 key,
+        AlgorithmParameters params,
+        SecureRandom        random)
+    throws InvalidKeyException, InvalidAlgorithmParameterException
+    {
+        AlgorithmParameterSpec  paramSpec = null;
+
+        if (params != null)
+        {
+            for (int i = 0; i != availableSpecs.length; i++)
+            {
+                try
+                {
+                    paramSpec = params.getParameterSpec(availableSpecs[i]);
+                    break;
+                }
+                catch (Exception e)
+                {
+                    continue;
+                }
+            }
+
+            if (paramSpec == null)
+            {
+                throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString());
+            }
+        }
+
+        engineParams = params;
+        engineInit(opmode, key, paramSpec, random);
+    }
+
+    protected void engineInit(
+        int                 opmode,
+        Key                 key,
+        SecureRandom        random)
+        throws InvalidKeyException
+    {
+        try
+        {
+            engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+        }
+        catch (InvalidAlgorithmParameterException e)
+        {
+            throw new IllegalArgumentException(e.getMessage());
+        }
+    }
+
+    protected byte[] engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen)
+    {
+        throw new RuntimeException("not supported for wrapping");
+    }
+
+    protected int engineUpdate(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset)
+        throws ShortBufferException
+    {
+        throw new RuntimeException("not supported for wrapping");
+    }
+
+    protected byte[] engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen)
+        throws IllegalBlockSizeException, BadPaddingException
+    {
+        return null;
+    }
+
+    protected int engineDoFinal(
+        byte[]  input,
+        int     inputOffset,
+        int     inputLen,
+        byte[]  output,
+        int     outputOffset)
+        throws IllegalBlockSizeException, BadPaddingException
+    {
+        return 0;
+    }
+
+    protected byte[] engineWrap(
+        Key     key)
+    throws IllegalBlockSizeException, java.security.InvalidKeyException
+    {
+        byte[] encoded = key.getEncoded();
+        if (encoded == null)
+        {
+            throw new InvalidKeyException("Cannot wrap key, null encoding.");
+        }
+
+        try
+        {
+            if (wrapEngine == null)
+            {
+                return engineDoFinal(encoded, 0, encoded.length);
+            }
+            else
+            {
+                return wrapEngine.wrap(encoded, 0, encoded.length);
+            }
+        }
+        catch (BadPaddingException e)
+        {
+            throw new IllegalBlockSizeException(e.getMessage());
+        }
+    }
+
+    protected Key engineUnwrap(
+        byte[]  wrappedKey,
+        String  wrappedKeyAlgorithm,
+        int     wrappedKeyType)
+    throws InvalidKeyException
+    {
+        byte[] encoded = null;
+        try
+        {
+            if (wrapEngine == null)
+            {
+                encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
+            }
+            else
+            {
+                encoded = wrapEngine.unwrap(wrappedKey, 0, wrappedKey.length);
+            }
+        }
+        catch (InvalidCipherTextException e)
+        {
+            throw new InvalidKeyException(e.getMessage());
+        }
+        catch (BadPaddingException e)
+        {
+            throw new InvalidKeyException(e.getMessage());
+        }
+        catch (IllegalBlockSizeException e2)
+        {
+            throw new InvalidKeyException(e2.getMessage());
+        }
+
+        if (wrappedKeyType == Cipher.SECRET_KEY)
+        {
+            return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
+        }
+        else if (wrappedKeyAlgorithm.equals("") && wrappedKeyType == Cipher.PRIVATE_KEY)
+        {
+            /*
+             * The caller doesnt know the algorithm as it is part of
+             * the encrypted data.
+             */
+            ASN1InputStream bIn = new ASN1InputStream(encoded);
+            PrivateKey      privKey = null;
+
+            try
+            {
+                ASN1Sequence         s = (ASN1Sequence)bIn.readObject();
+                PrivateKeyInfo       in = new PrivateKeyInfo(s);
+
+                DERObjectIdentifier  oid = in.getAlgorithmId().getObjectId();
+
+                // BEGIN android-removed
+                // if (oid.equals(X9ObjectIdentifiers.id_ecPublicKey))
+                // {
+                //     privKey = new JCEECPrivateKey(in);
+                // }
+                // else if (oid.equals(CryptoProObjectIdentifiers.gostR3410_94))
+                // {
+                //     privKey = new JDKGOST3410PrivateKey(in);
+                // }
+                // else if (oid.equals(X9ObjectIdentifiers.id_dsa))
+                // END android-removed
+                // BEGIN android-added
+                if (oid.equals(X9ObjectIdentifiers.id_dsa))
+                // END android-added
+                {
+                    privKey = new JDKDSAPrivateKey(in);
+                }
+                else if (oid.equals(PKCSObjectIdentifiers.dhKeyAgreement))
+                {
+                    privKey = new JCEDHPrivateKey(in);
+                }
+                else if (oid.equals(X9ObjectIdentifiers.dhpublicnumber))
+                {
+                    privKey = new JCEDHPrivateKey(in);
+                }
+                else    // the old standby!
+                {
+                    privKey = new JCERSAPrivateCrtKey(in);
+                }
+            }
+            catch (Exception e)
+            {
+                throw new InvalidKeyException("Invalid key encoding.");
+            }
+
+            return privKey;
+        }
+        else
+        {
+            try
+            {
+                KeyFactory kf = KeyFactory.getInstance(wrappedKeyAlgorithm, "BC");
+
+                if (wrappedKeyType == Cipher.PUBLIC_KEY)
+                {
+                    return kf.generatePublic(new X509EncodedKeySpec(encoded));
+                }
+                else if (wrappedKeyType == Cipher.PRIVATE_KEY)
+                {
+                    return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
+                }
+            }
+            catch (NoSuchProviderException e)
+            {
+                throw new InvalidKeyException("Unknown key type " + e.getMessage());
+            }
+            catch (NoSuchAlgorithmException e)
+            {
+                throw new InvalidKeyException("Unknown key type " + e.getMessage());
+            }
+            catch (InvalidKeySpecException e2)
+            {
+                throw new InvalidKeyException("Unknown key type " + e2.getMessage());
+            }
+
+            throw new InvalidKeyException("Unknown key type " + wrappedKeyType);
+        }
+    }
+
+    //
+    // classes that inherit directly from us
+    //
+    public static class AESWrap
+        extends WrapCipherSpi
+    {
+        public AESWrap()
+        {
+            super(new AESWrapEngine());
+        }
+    }
+
+    public static class DESEDEWrap
+        extends WrapCipherSpi
+    {
+        public DESEDEWrap()
+        {
+            super(new DESedeWrapEngine());
+        }
+    }
+
+// BEGIN android-removed
+//    public static class RC2Wrap
+//        extends WrapCipherSpi
+//    {
+//        public RC2Wrap()
+//        {
+//            super(new RC2WrapEngine());
+//        }
+//    }
+// END android-removed
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java
new file mode 100644
index 0000000..ebf37fb
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java
@@ -0,0 +1,241 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRLEntry;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.GeneralNames;
+import org.bouncycastle.asn1.x509.TBSCertList;
+import org.bouncycastle.asn1.x509.X509Extension;
+import org.bouncycastle.asn1.x509.X509Extensions;
+import org.bouncycastle.x509.extension.X509ExtensionUtil;
+
+/**
+ * The following extensions are listed in RFC 2459 as relevant to CRL Entries
+ * 
+ * ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer
+ * (critical)
+ */
+public class X509CRLEntryObject extends X509CRLEntry
+{
+    private TBSCertList.CRLEntry c;
+
+    private boolean isIndirect = false;
+
+    private X500Principal previousCertificateIssuer = null;
+
+    public X509CRLEntryObject(TBSCertList.CRLEntry c)
+    {
+        this.c = c;
+    }
+
+    /**
+     * Constructor for CRLEntries of indirect CRLs. If <code>isIndirect</code>
+     * is <code>false</code> {@link #getCertificateIssuer()} will always
+     * return <code>null</code>, <code>previousCertificateIssuer</code> is
+     * ignored. If this <code>isIndirect</code> is specified and this CRLEntry
+     * has no certificate issuer CRL entry extension
+     * <code>previousCertificateIssuer</code> is returned by
+     * {@link #getCertificateIssuer()}.
+     * 
+     * @param c
+     *            TBSCertList.CRLEntry object.
+     * @param isIndirect
+     *            <code>true</code> if the corresponding CRL is a indirect
+     *            CRL.
+     * @param previousCertificateIssuer
+     *            Certificate issuer of the previous CRLEntry.
+     */
+    public X509CRLEntryObject(
+        TBSCertList.CRLEntry c,
+        boolean isIndirect,
+        X500Principal previousCertificateIssuer)
+    {
+        this.c = c;
+        this.isIndirect = isIndirect;
+        this.previousCertificateIssuer = previousCertificateIssuer;
+    }
+
+    /**
+     * Will return true if any extensions are present and marked as critical as
+     * we currently dont handle any extensions!
+     */
+    public boolean hasUnsupportedCriticalExtension()
+    {
+        Set extns = getCriticalExtensionOIDs();
+        if (extns != null && !extns.isEmpty())
+        {
+            return true;
+        }
+
+        return false;
+    }
+
+    public X500Principal getCertificateIssuer()
+    {
+        if (!isIndirect)
+        {
+            return null;
+        }
+
+        byte[] ext = getExtensionValue(X509Extensions.CertificateIssuer.getId());
+        if (ext == null)
+        {
+            return previousCertificateIssuer;
+        }
+
+        try
+        {
+            GeneralName[] names = GeneralNames.getInstance(
+                    X509ExtensionUtil.fromExtensionValue(ext)).getNames();
+            for (int i = 0; i < names.length; i++)
+            {
+                if (names[i].getTagNo() == GeneralName.directoryName)
+                {
+                    return new X500Principal(names[i].getName().getDERObject().getDEREncoded());
+                }
+            }
+            throw new RuntimeException(
+                    "Cannot extract directory name from certificate issuer CRL entry extension");
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException(
+                    "Cannot extract certificate issuer CRL entry extension "
+                            + e);
+        }
+    }
+
+    private Set getExtensionOIDs(boolean critical)
+    {
+        X509Extensions extensions = c.getExtensions();
+
+        if (extensions != null)
+        {
+            Set set = new HashSet();
+            Enumeration e = extensions.oids();
+
+            while (e.hasMoreElements())
+            {
+                DERObjectIdentifier oid = (DERObjectIdentifier) e.nextElement();
+                X509Extension ext = extensions.getExtension(oid);
+
+                if (critical == ext.isCritical())
+                {
+                    set.add(oid.getId());
+                }
+            }
+
+            return set;
+        }
+
+        return null;
+    }
+
+    public Set getCriticalExtensionOIDs()
+    {
+        return getExtensionOIDs(true);
+    }
+
+    public Set getNonCriticalExtensionOIDs()
+    {
+        return getExtensionOIDs(false);
+    }
+
+    public byte[] getExtensionValue(String oid)
+    {
+        X509Extensions exts = c.getExtensions();
+
+        if (exts != null)
+        {
+            X509Extension ext = exts.getExtension(new DERObjectIdentifier(oid));
+
+            if (ext != null)
+            {
+                try
+                {
+                    return ext.getValue().getEncoded();
+                }
+                catch (Exception e)
+                {
+                    throw new RuntimeException("error encoding " + e.toString());
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public byte[] getEncoded()
+        throws CRLException
+    {
+        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+        DEROutputStream dOut = new DEROutputStream(bOut);
+
+        try
+        {
+            dOut.writeObject(c);
+
+            return bOut.toByteArray();
+        }
+        catch (IOException e)
+        {
+            throw new CRLException(e.toString());
+        }
+    }
+
+    public BigInteger getSerialNumber()
+    {
+        return c.getUserCertificate().getValue();
+    }
+
+    public Date getRevocationDate()
+    {
+        return c.getRevocationDate().getDate();
+    }
+
+    public boolean hasExtensions()
+    {
+        return c.getExtensions() != null;
+    }
+
+    public String toString()
+    {
+        StringBuffer buf = new StringBuffer();
+        String nl = System.getProperty("line.separator");
+
+        buf.append("      userCertificate: ").append(this.getSerialNumber()).append(nl);
+        buf.append("       revocationDate: ").append(this.getRevocationDate()).append(nl);
+
+        X509Extensions extensions = c.getExtensions();
+
+        if (extensions != null)
+        {
+            Enumeration e = extensions.oids();
+            if (e.hasMoreElements())
+            {
+                buf.append("   crlEntryExtensions:").append(nl);
+
+                while (e.hasMoreElements())
+                {
+                    DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+                    X509Extension ext = extensions.getExtension(oid);
+                    buf.append(ext);
+                }
+            }
+        }
+
+        return buf.toString();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java
new file mode 100644
index 0000000..7533947
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java
@@ -0,0 +1,398 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1OutputStream;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.asn1.x509.CertificateList;
+import org.bouncycastle.asn1.x509.IssuingDistributionPoint;
+import org.bouncycastle.asn1.x509.TBSCertList;
+import org.bouncycastle.asn1.x509.X509Extension;
+import org.bouncycastle.asn1.x509.X509Extensions;
+import org.bouncycastle.jce.X509Principal;
+import org.bouncycastle.x509.extension.X509ExtensionUtil;
+
+/**
+ * The following extensions are listed in RFC 2459 as relevant to CRLs
+ *
+ * Authority Key Identifier
+ * Issuer Alternative Name
+ * CRL Number
+ * Delta CRL Indicator (critical)
+ * Issuing Distribution Point (critical)
+ */
+public class X509CRLObject
+    extends X509CRL
+{
+    private CertificateList c;
+    private String sigAlgName;
+    private byte[] sigAlgParams;
+
+    public X509CRLObject(
+        CertificateList c)
+        throws CRLException
+    {
+        this.c = c;
+        
+        try
+        {
+            this.sigAlgName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+            
+            if (c.getSignatureAlgorithm().getParameters() != null)
+            {
+                this.sigAlgParams = ((ASN1Encodable)c.getSignatureAlgorithm().getParameters()).getDEREncoded();
+            }
+            else
+            {
+                this.sigAlgParams = null;
+            }
+        }
+        catch (Exception e)
+        {
+            throw new CRLException("CRL contents invalid: " + e);
+        }
+    }
+
+    /**
+     * Will return true if any extensions are present and marked
+     * as critical as we currently dont handle any extensions!
+     */
+    public boolean hasUnsupportedCriticalExtension()
+    {
+        Set extns = getCriticalExtensionOIDs();
+        if (extns != null && !extns.isEmpty())
+        {
+            return true;
+        }
+
+        return false;
+    }
+
+    private Set getExtensionOIDs(boolean critical)
+    {
+        if (this.getVersion() == 2)
+        {
+            Set             set = new HashSet();
+            X509Extensions  extensions = c.getTBSCertList().getExtensions();
+            Enumeration     e = extensions.oids();
+
+            while (e.hasMoreElements())
+            {
+                DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+                X509Extension       ext = extensions.getExtension(oid);
+
+                if (critical == ext.isCritical())
+                {
+                    set.add(oid.getId());
+                }
+            }
+
+            return set;
+        }
+
+        return null;
+    }
+
+    public Set getCriticalExtensionOIDs()
+    {
+        return getExtensionOIDs(true);
+    }
+
+    public Set getNonCriticalExtensionOIDs()
+    {
+        return getExtensionOIDs(false);
+    }
+
+    public byte[] getExtensionValue(String oid)
+    {
+        X509Extensions exts = c.getTBSCertList().getExtensions();
+
+        if (exts != null)
+        {
+            X509Extension   ext = exts.getExtension(new DERObjectIdentifier(oid));
+
+            if (ext != null)
+            {
+                ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+                DEROutputStream dOut = new DEROutputStream(bOut);
+
+                try
+                {
+                    dOut.writeObject(ext.getValue());
+
+                    return bOut.toByteArray();
+                }
+                catch (Exception e)
+                {
+                    throw new RuntimeException("error encoding " + e.toString());
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public byte[] getEncoded()
+        throws CRLException
+    {
+        ByteArrayOutputStream    bOut = new ByteArrayOutputStream();
+        DEROutputStream            dOut = new DEROutputStream(bOut);
+
+        try
+        {
+            dOut.writeObject(c);
+
+            return bOut.toByteArray();
+        }
+        catch (IOException e)
+        {
+            throw new CRLException(e.toString());
+        }
+    }
+
+    public void verify(PublicKey key)
+        throws CRLException,  NoSuchAlgorithmException,
+            InvalidKeyException, NoSuchProviderException, SignatureException
+    {
+        verify(key, "BC");
+    }
+
+    public void verify(PublicKey key, String sigProvider)
+        throws CRLException, NoSuchAlgorithmException,
+            InvalidKeyException, NoSuchProviderException, SignatureException
+    {
+        if (!c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature()))
+        {
+            throw new CRLException("Signature algorithm on CertifcateList does not match TBSCertList.");
+        }
+
+        Signature sig = Signature.getInstance(getSigAlgName(), sigProvider);
+
+        sig.initVerify(key);
+        sig.update(this.getTBSCertList());
+        if (!sig.verify(this.getSignature()))
+        {
+            throw new SignatureException("CRL does not verify with supplied public key.");
+        }
+    }
+
+    public int getVersion()
+    {
+        return c.getVersion();
+    }
+
+    public Principal getIssuerDN()
+    {
+        return new X509Principal(c.getIssuer());
+    }
+
+    public X500Principal getIssuerX500Principal()
+    {
+        try
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
+
+            aOut.writeObject(c.getIssuer());
+
+            return new X500Principal(bOut.toByteArray());
+        }
+        catch (IOException e)
+        {
+            throw new IllegalStateException("can't encode issuer DN");
+        }
+    }
+
+    public Date getThisUpdate()
+    {
+        return c.getThisUpdate().getDate();
+    }
+
+    public Date getNextUpdate()
+    {
+        if (c.getNextUpdate() != null)
+        {
+            return c.getNextUpdate().getDate();
+        }
+
+        return null;
+    }
+
+    public X509CRLEntry getRevokedCertificate(BigInteger serialNumber)
+    {
+        TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
+        boolean isIndirect = isIndirectCRL();
+        if (certs != null)
+        {
+            X500Principal previousCertificateIssuer = getIssuerX500Principal();
+            for (int i = 0; i < certs.length; i++)
+            {
+                X509CRLEntryObject crlentry = new X509CRLEntryObject(certs[i],
+                        isIndirect, previousCertificateIssuer);
+                previousCertificateIssuer = crlentry.getCertificateIssuer();
+                if (crlentry.getSerialNumber().equals(serialNumber))
+                {
+                    return crlentry;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    private boolean isIndirectCRL()
+    {
+        byte[] idp = getExtensionValue(X509Extensions.IssuingDistributionPoint.getId());
+        boolean isIndirect = false;
+        try
+        {
+            if (idp != null)
+            {
+                isIndirect = IssuingDistributionPoint.getInstance(
+                        X509ExtensionUtil.fromExtensionValue(idp))
+                        .isIndirectCRL();
+            }
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException(
+                    "Exception reading IssuingDistributionPoint" + e);
+        }
+
+        return isIndirect;
+    }
+  
+    public Set getRevokedCertificates()
+    {
+        TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
+        boolean isIndirect = isIndirectCRL();
+        if (certs != null)
+        {
+            Set set = new HashSet();
+            X500Principal previousCertificateIssuer = getIssuerX500Principal();
+            for (int i = 0; i < certs.length; i++)
+            {
+                X509CRLEntryObject crlentry = new X509CRLEntryObject(certs[i],
+                        isIndirect, previousCertificateIssuer);
+                set.add(crlentry);
+                previousCertificateIssuer = crlentry.getCertificateIssuer();
+            }
+
+            return set;
+        }
+
+        return null;
+    }
+  
+    public byte[] getTBSCertList()
+        throws CRLException
+    {
+        ByteArrayOutputStream    bOut = new ByteArrayOutputStream();
+        DEROutputStream            dOut = new DEROutputStream(bOut);
+
+        try
+        {
+            dOut.writeObject(c.getTBSCertList());
+
+            return bOut.toByteArray();
+        }
+        catch (IOException e)
+        {
+            throw new CRLException(e.toString());
+        }
+    }
+
+    public byte[] getSignature()
+    {
+        return c.getSignature().getBytes();
+    }
+
+    public String getSigAlgName()
+    {
+        return sigAlgName;
+    }
+
+    public String getSigAlgOID()
+    {
+        return c.getSignatureAlgorithm().getObjectId().getId();
+    }
+
+    public byte[] getSigAlgParams()
+    {
+        if (sigAlgParams != null)
+        {
+            byte[] tmp = new byte[sigAlgParams.length];
+            
+            System.arraycopy(sigAlgParams, 0, tmp, 0, tmp.length);
+            
+            return tmp;
+        }
+        
+        return null;
+    }
+
+    /**
+     * Returns a string representation of this CRL.
+     *
+     * @return a string representation of this CRL.
+     */
+    public String toString()
+    {
+        return "X.509 CRL";
+    }
+
+    /**
+     * Checks whether the given certificate is on this CRL.
+     *
+     * @param cert the certificate to check for.
+     * @return true if the given certificate is on this CRL,
+     * false otherwise.
+     */
+    public boolean isRevoked(Certificate cert)
+    {
+        if (!cert.getType().equals("X.509"))
+        {
+            throw new RuntimeException("X.509 CRL used with non X.509 Cert");
+        }
+
+        TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
+
+        if (certs != null)
+        {
+            BigInteger serial = ((X509Certificate)cert).getSerialNumber();
+
+            for (int i = 0; i < certs.length; i++)
+            {
+                if (certs[i].getUserCertificate().getValue().equals(serial))
+                {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+}
+
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java
new file mode 100644
index 0000000..4ba3db3
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java
@@ -0,0 +1,772 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1OutputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERBoolean;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERIA5String;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DEROutputStream;
+// BEGIN android-added
+import org.bouncycastle.asn1.OrderedTable;
+// END android-added
+import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
+import org.bouncycastle.asn1.misc.NetscapeCertType;
+import org.bouncycastle.asn1.misc.NetscapeRevocationURL;
+import org.bouncycastle.asn1.misc.VerisignCzagExtension;
+import org.bouncycastle.asn1.util.ASN1Dump;
+import org.bouncycastle.asn1.x509.BasicConstraints;
+import org.bouncycastle.asn1.x509.KeyUsage;
+import org.bouncycastle.asn1.x509.X509CertificateStructure;
+import org.bouncycastle.asn1.x509.X509Extension;
+import org.bouncycastle.asn1.x509.X509Extensions;
+import org.bouncycastle.jce.X509Principal;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.encoders.Hex;
+
+public class X509CertificateObject
+    extends X509Certificate
+    implements PKCS12BagAttributeCarrier
+{
+    private X509CertificateStructure    c;
+    // BEGIN android-changed
+    private OrderedTable                pkcs12 = new OrderedTable();
+    // END android-changed
+
+    public X509CertificateObject(
+        X509CertificateStructure    c)
+    {
+        this.c = c;
+    }
+
+    public void checkValidity()
+        throws CertificateExpiredException, CertificateNotYetValidException
+    {
+        this.checkValidity(new Date());
+    }
+
+    public void checkValidity(
+        Date    date)
+        throws CertificateExpiredException, CertificateNotYetValidException
+    {
+        if (date.after(this.getNotAfter()))
+        {
+            throw new CertificateExpiredException("certificate expired on " + c.getEndDate().getTime());
+        }
+
+        if (date.before(this.getNotBefore()))
+        {
+            throw new CertificateNotYetValidException("certificate not valid till " + c.getStartDate().getTime());
+        }
+    }
+
+    public int getVersion()
+    {
+        return c.getVersion();
+    }
+
+    public BigInteger getSerialNumber()
+    {
+        return c.getSerialNumber().getValue();
+    }
+
+    public Principal getIssuerDN()
+    {
+        return new X509Principal(c.getIssuer());
+    }
+
+    public X500Principal getIssuerX500Principal()
+    {
+        try
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
+
+            aOut.writeObject(c.getIssuer());
+
+            return new X500Principal(bOut.toByteArray());
+        }
+        catch (IOException e)
+        {
+            throw new IllegalStateException("can't encode issuer DN");
+        }
+    }
+
+    public Principal getSubjectDN()
+    {
+        return new X509Principal(c.getSubject());
+    }
+
+    public X500Principal getSubjectX500Principal()
+    {
+        try
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
+
+            aOut.writeObject(c.getSubject());
+
+            return new X500Principal(bOut.toByteArray());
+        }
+        catch (IOException e)
+        {
+            throw new IllegalStateException("can't encode issuer DN");
+        }
+    }
+
+    public Date getNotBefore()
+    {
+        return c.getStartDate().getDate();
+    }
+
+    public Date getNotAfter()
+    {
+        return c.getEndDate().getDate();
+    }
+
+    public byte[] getTBSCertificate()
+        throws CertificateEncodingException
+    {
+        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+        DEROutputStream         dOut = new DEROutputStream(bOut);
+
+        try
+        {
+            dOut.writeObject(c.getTBSCertificate());
+
+            return bOut.toByteArray();
+        }
+        catch (IOException e)
+        {
+            throw new CertificateEncodingException(e.toString());
+        }
+    }
+
+    public byte[] getSignature()
+    {
+        return c.getSignature().getBytes();
+    }
+
+    /**
+     * return a more "meaningful" representation for the signature algorithm used in
+     * the certficate.
+     */
+    public String getSigAlgName()
+    {
+        Provider    prov = Security.getProvider("BC");
+        String      algName = prov.getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
+
+        if (algName != null)
+        {
+            return algName;
+        }
+
+        Provider[] provs = Security.getProviders();
+
+        //
+        // search every provider looking for a real algorithm
+        //
+        for (int i = 0; i != provs.length; i++)
+        {
+            algName = provs[i].getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
+            if (algName != null)
+            {
+                return algName;
+            }
+        }
+
+        return this.getSigAlgOID();
+    }
+
+    /**
+     * return the object identifier for the signature.
+     */
+    public String getSigAlgOID()
+    {
+        return c.getSignatureAlgorithm().getObjectId().getId();
+    }
+
+    /**
+     * return the signature parameters, or null if there aren't any.
+     */
+    public byte[] getSigAlgParams()
+    {
+        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+
+        if (c.getSignatureAlgorithm().getParameters() != null)
+        {
+            try
+            {
+                DEROutputStream         dOut = new DEROutputStream(bOut);
+
+                dOut.writeObject(c.getSignatureAlgorithm().getParameters());
+            }
+            catch (Exception e)
+            {
+                throw new RuntimeException("exception getting sig parameters " + e);
+            }
+
+            return bOut.toByteArray();
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+    public boolean[] getIssuerUniqueID()
+    {
+        DERBitString    id = c.getTBSCertificate().getIssuerUniqueId();
+
+        if (id != null)
+        {
+            byte[]          bytes = id.getBytes();
+            boolean[]       boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+            for (int i = 0; i != boolId.length; i++)
+            {
+                boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+            }
+
+            return boolId;
+        }
+            
+        return null;
+    }
+
+    public boolean[] getSubjectUniqueID()
+    {
+        DERBitString    id = c.getTBSCertificate().getSubjectUniqueId();
+
+        if (id != null)
+        {
+            byte[]          bytes = id.getBytes();
+            boolean[]       boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+            for (int i = 0; i != boolId.length; i++)
+            {
+                boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+            }
+
+            return boolId;
+        }
+            
+        return null;
+    }
+
+    public boolean[] getKeyUsage()
+    {
+        byte[]  bytes = this.getExtensionBytes("2.5.29.15");
+        int     length = 0;
+
+        if (bytes != null)
+        {
+            try
+            {
+                ASN1InputStream dIn = new ASN1InputStream(bytes);
+                DERBitString    bits = (DERBitString)dIn.readObject();
+
+                bytes = bits.getBytes();
+                length = (bytes.length * 8) - bits.getPadBits();
+            }
+            catch (Exception e)
+            {
+                throw new RuntimeException("error processing key usage extension");
+            }
+
+            boolean[]       keyUsage = new boolean[(length < 9) ? 9 : length];
+
+            for (int i = 0; i != length; i++)
+            {
+                keyUsage[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+            }
+
+            return keyUsage;
+        }
+
+        return null;
+    }
+
+    public List getExtendedKeyUsage() 
+        throws CertificateParsingException
+    {
+        byte[]  bytes = this.getExtensionBytes("2.5.29.37");
+        int     length = 0;
+
+        if (bytes != null)
+        {
+            try
+            {
+                ASN1InputStream dIn = new ASN1InputStream(bytes);
+                ASN1Sequence    seq = (ASN1Sequence)dIn.readObject();
+                List            list = new ArrayList();
+
+                for (int i = 0; i != seq.size(); i++)
+                {
+                    list.add(((DERObjectIdentifier)seq.getObjectAt(i)).getId());
+                }
+                
+                return Collections.unmodifiableList(list);
+            }
+            catch (Exception e)
+            {
+                throw new CertificateParsingException("error processing extended key usage extension");
+            }
+        }
+
+        return null;
+    }
+    
+    public int getBasicConstraints()
+    {
+        byte[]  bytes = this.getExtensionBytes("2.5.29.19");
+
+        if (bytes != null)
+        {
+            try
+            {
+                ASN1InputStream dIn = new ASN1InputStream(bytes);
+                ASN1Sequence    seq = (ASN1Sequence)dIn.readObject();
+
+                if (seq.size() == 2)
+                {
+                    if (((DERBoolean)seq.getObjectAt(0)).isTrue())
+                    {
+                        return ((DERInteger)seq.getObjectAt(1)).getValue().intValue();
+                    }
+                    else
+                    {
+                        return -1;
+                    }
+                }
+                else if (seq.size() == 1)
+                {
+                    if (seq.getObjectAt(0) instanceof DERBoolean)
+                    {
+                        if (((DERBoolean)seq.getObjectAt(0)).isTrue())
+                        {
+                            return Integer.MAX_VALUE;
+                        }
+                        else
+                        {
+                            return -1;
+                        }
+                    }
+                    else
+                    {
+                        return -1;
+                    }
+                }
+            }
+            catch (Exception e)
+            {
+                throw new RuntimeException("error processing basic constraints extension");
+            }
+        }
+
+        return -1;
+    }
+
+    public Set getCriticalExtensionOIDs() 
+    {
+        if (this.getVersion() == 3)
+        {
+            Set             set = new HashSet();
+            X509Extensions  extensions = c.getTBSCertificate().getExtensions();
+
+            if (extensions != null)
+            {
+                Enumeration     e = extensions.oids();
+
+                while (e.hasMoreElements())
+                {
+                    DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+                    X509Extension       ext = extensions.getExtension(oid);
+
+                    if (ext.isCritical())
+                    {
+                        set.add(oid.getId());
+                    }
+                }
+
+                return set;
+            }
+        }
+
+        return null;
+    }
+
+    private byte[] getExtensionBytes(String oid)
+    {
+        X509Extensions exts = c.getTBSCertificate().getExtensions();
+
+        if (exts != null)
+        {
+            X509Extension   ext = exts.getExtension(new DERObjectIdentifier(oid));
+            if (ext != null)
+            {
+                return ext.getValue().getOctets();
+            }
+        }
+
+        return null;
+    }
+
+    public byte[] getExtensionValue(String oid) 
+    {
+        X509Extensions exts = c.getTBSCertificate().getExtensions();
+
+        if (exts != null)
+        {
+            X509Extension   ext = exts.getExtension(new DERObjectIdentifier(oid));
+
+            if (ext != null)
+            {
+                ByteArrayOutputStream    bOut = new ByteArrayOutputStream();
+                DEROutputStream            dOut = new DEROutputStream(bOut);
+                
+                try
+                {
+                    dOut.writeObject(ext.getValue());
+
+                    return bOut.toByteArray();
+                }
+                catch (Exception e)
+                {
+                    throw new RuntimeException("error encoding " + e.toString());
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public Set getNonCriticalExtensionOIDs() 
+    {
+        if (this.getVersion() == 3)
+        {
+            Set             set = new HashSet();
+            X509Extensions  extensions = c.getTBSCertificate().getExtensions();
+
+            if (extensions != null)
+            {
+                Enumeration     e = extensions.oids();
+
+                while (e.hasMoreElements())
+                {
+                    DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+                    X509Extension       ext = extensions.getExtension(oid);
+
+                    if (!ext.isCritical())
+                    {
+                        set.add(oid.getId());
+                    }
+                }
+
+                return set;
+            }
+        }
+
+        return null;
+    }
+
+    public boolean hasUnsupportedCriticalExtension()
+    {
+        if (this.getVersion() == 3)
+        {
+            X509Extensions  extensions = c.getTBSCertificate().getExtensions();
+
+            if (extensions != null)
+            {
+                Enumeration     e = extensions.oids();
+
+                while (e.hasMoreElements())
+                {
+                    DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+                    if (oid.getId().equals("2.5.29.15")
+                       || oid.getId().equals("2.5.29.19"))
+                    {
+                        continue;
+                    }
+
+                    X509Extension       ext = extensions.getExtension(oid);
+
+                    if (ext.isCritical())
+                    {
+                        return true;
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    public PublicKey getPublicKey()
+    {
+        return JDKKeyFactory.createPublicKeyFromPublicKeyInfo(c.getSubjectPublicKeyInfo());
+    }
+
+    public byte[] getEncoded()
+        throws CertificateEncodingException
+    {
+        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+        DEROutputStream         dOut = new DEROutputStream(bOut);
+
+        try
+        {
+            dOut.writeObject(c);
+
+            return bOut.toByteArray();
+        }
+        catch (IOException e)
+        {
+            throw new CertificateEncodingException(e.toString());
+        }
+    }
+
+    public boolean equals(
+        Object o)
+    {
+        if (o == this)
+        {
+            return true;
+        }
+        
+        if (!(o instanceof Certificate))
+        {
+            return false;
+        }
+
+        Certificate other = (Certificate)o;
+        
+        try
+        {
+            byte[] b1 = this.getEncoded();
+            byte[] b2 = other.getEncoded();
+            
+            return Arrays.areEqual(b1, b2);
+        }
+        catch (CertificateEncodingException e)
+        {
+            return false;
+        }
+    }
+    
+    public int hashCode()
+    {
+        return c.hashCode();
+    }
+    
+    public void setBagAttribute(
+        DERObjectIdentifier oid,
+        DEREncodable        attribute)
+    {
+        // BEGIN android-changed
+        pkcs12.add(oid, attribute);
+        // END android-changed
+    }
+
+    public DEREncodable getBagAttribute(
+        DERObjectIdentifier oid)
+    {
+        // BEGIN android-changed
+        return (DEREncodable)pkcs12.get(oid);
+        // END android-changed
+    }
+
+    public Enumeration getBagAttributeKeys()
+    {
+        // BEGIN android-changed
+        return pkcs12.getKeys();
+        // END android-changed
+    }
+
+    public String toString()
+    {
+        StringBuffer    buf = new StringBuffer();
+        String          nl = System.getProperty("line.separator");
+
+        buf.append("  [0]         Version: ").append(this.getVersion()).append(nl);
+        buf.append("         SerialNumber: ").append(this.getSerialNumber()).append(nl);
+        buf.append("             IssuerDN: ").append(this.getIssuerDN()).append(nl);
+        buf.append("           Start Date: ").append(this.getNotBefore()).append(nl);
+        buf.append("           Final Date: ").append(this.getNotAfter()).append(nl);
+        buf.append("            SubjectDN: ").append(this.getSubjectDN()).append(nl);
+        buf.append("           Public Key: ").append(this.getPublicKey()).append(nl);
+        buf.append("  Signature Algorithm: ").append(this.getSigAlgName()).append(nl);
+
+        byte[]  sig = this.getSignature();
+
+        buf.append("            Signature: ").append(new String(Hex.encode(sig, 0, 20))).append(nl);
+        for (int i = 20; i < sig.length; i += 20)
+        {
+            if (i < sig.length - 20)
+            {
+                buf.append("                       ").append(new String(Hex.encode(sig, i, 20))).append(nl);
+            }
+            else
+            {
+                buf.append("                       ").append(new String(Hex.encode(sig, i, sig.length - i))).append(nl);
+            }
+        }
+
+        X509Extensions  extensions = c.getTBSCertificate().getExtensions();
+
+        if (extensions != null)
+        {
+            Enumeration     e = extensions.oids();
+
+            if (e.hasMoreElements())
+            {
+                buf.append("       Extensions: \n");
+            }
+
+            while (e.hasMoreElements())
+            {
+                DERObjectIdentifier     oid = (DERObjectIdentifier)e.nextElement();
+                X509Extension           ext = extensions.getExtension(oid);
+
+                if (ext.getValue() != null)
+                {
+                    byte[]                  octs = ext.getValue().getOctets();
+                    ASN1InputStream         dIn = new ASN1InputStream(octs);
+                    buf.append("                       critical(").append(ext.isCritical()).append(") ");
+                    try
+                    {
+                        if (oid.equals(X509Extensions.BasicConstraints))
+                        {
+                            buf.append(new BasicConstraints((ASN1Sequence)dIn.readObject())).append(nl);
+                        }
+                        else if (oid.equals(X509Extensions.KeyUsage))
+                        {
+                            buf.append(new KeyUsage((DERBitString)dIn.readObject())).append(nl);
+                        }
+                        else if (oid.equals(MiscObjectIdentifiers.netscapeCertType))
+                        {
+                            buf.append(new NetscapeCertType((DERBitString)dIn.readObject())).append(nl);
+                        }
+                        else if (oid.equals(MiscObjectIdentifiers.netscapeRevocationURL))
+                        {
+                            buf.append(new NetscapeRevocationURL((DERIA5String)dIn.readObject())).append(nl);
+                        }
+                        else if (oid.equals(MiscObjectIdentifiers.verisignCzagExtension))
+                        {
+                            buf.append(new VerisignCzagExtension((DERIA5String)dIn.readObject())).append(nl);
+                        }
+                        else 
+                        {
+                            buf.append(oid.getId());
+                            buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl);
+                            //buf.append(" value = ").append("*****").append(nl);
+                        }
+                    }
+                    catch (Exception ex)
+                    {
+                        buf.append(oid.getId());
+                   //     buf.append(" value = ").append(new String(Hex.encode(ext.getValue().getOctets()))).append(nl);
+                        buf.append(" value = ").append("*****").append(nl);
+                    }
+                }
+                else
+                {
+                    buf.append(nl);
+                }
+            }
+        }
+
+        return buf.toString();
+    }
+
+    public final void verify(
+        PublicKey   key)
+        throws CertificateException, NoSuchAlgorithmException,
+        InvalidKeyException, NoSuchProviderException, SignatureException
+    {
+        Signature   signature = null;
+        String      sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+        
+        try
+        {
+            signature = Signature.getInstance(sigName, "BC");
+        }
+        catch (Exception e)
+        {
+            signature = Signature.getInstance(sigName);
+        }
+        
+        checkSignature(key, signature);
+    }
+    
+    public final void verify(
+        PublicKey   key,
+        String      sigProvider)
+        throws CertificateException, NoSuchAlgorithmException,
+        InvalidKeyException, NoSuchProviderException, SignatureException
+    {
+        String    sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+        Signature signature = Signature.getInstance(sigName, sigProvider);
+        
+        checkSignature(key, signature);
+    }
+
+    private void checkSignature(
+        PublicKey key, 
+        Signature signature) 
+        throws CertificateException, NoSuchAlgorithmException, 
+            SignatureException, InvalidKeyException, CertificateEncodingException
+    {
+        if (!c.getSignatureAlgorithm().equals(c.getTBSCertificate().getSignature()))
+        {
+            throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
+        }
+
+        DEREncodable params = c.getSignatureAlgorithm().getParameters();
+        
+        X509SignatureUtil.setSignatureParameters(signature, params);
+
+        signature.initVerify(key);
+
+        signature.update(this.getTBSCertificate());
+
+        if (!signature.verify(this.getSignature()))
+        {
+            throw new InvalidKeyException("Public key presented not for certificate signature");
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java
new file mode 100644
index 0000000..2a79524
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java
@@ -0,0 +1,140 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.PSSParameterSpec;
+
+import org.bouncycastle.asn1.ASN1Null;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
+import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+class X509SignatureUtil
+{
+    // BEGIN android-changed
+    private static final ASN1Null       derNull = DERNull.THE_ONE;
+    // END android-changed
+    
+    static void setSignatureParameters(
+        Signature signature,
+        DEREncodable params) 
+        throws NoSuchAlgorithmException, SignatureException, InvalidKeyException
+    {
+        if (params != null && !derNull.equals(params))
+        {
+            AlgorithmParameters  sigParams = AlgorithmParameters.getInstance(signature.getAlgorithm(), signature.getProvider());
+            
+            try
+            {
+                sigParams.init(params.getDERObject().getDEREncoded());
+            }
+            catch (IOException e)
+            {
+                throw new SignatureException("IOException decoding parameters: " + e.getMessage());
+            }
+            
+            if (signature.getAlgorithm().endsWith("MGF1"))
+            {
+                try
+                {
+                    signature.setParameter(sigParams.getParameterSpec(PSSParameterSpec.class));
+                }
+                catch (GeneralSecurityException e)
+                {
+                    throw new SignatureException("Exception extracting parameters: " + e.getMessage());
+                }
+            }
+        }
+    }
+    
+    static String getSignatureName(
+        AlgorithmIdentifier sigAlgId) 
+    {
+        DEREncodable params = sigAlgId.getParameters();
+        
+        if (params != null && !derNull.equals(params))
+        {
+            if (sigAlgId.getObjectId().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+            {
+                RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
+                
+                return getDigestAlgName(rsaParams.getHashAlgorithm().getObjectId()) + "withRSAandMGF1";
+            }
+            if (sigAlgId.getObjectId().equals(X9ObjectIdentifiers.ecdsa_with_SHA2))
+            {
+                ASN1Sequence ecDsaParams = ASN1Sequence.getInstance(params);
+                
+                return getDigestAlgName((DERObjectIdentifier)ecDsaParams.getObjectAt(0)) + "withECDSA";
+            }
+        }
+
+        return sigAlgId.getObjectId().getId();
+    }
+    
+    /**
+     * Return the digest algorithm using one of the standard JCA string
+     * representations rather the the algorithm identifier (if possible).
+     */
+    private static String getDigestAlgName(
+        DERObjectIdentifier digestAlgOID)
+    {
+        if (PKCSObjectIdentifiers.md5.equals(digestAlgOID))
+        {
+            return "MD5";
+        }
+        else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID))
+        {
+            return "SHA1";
+        }
+        else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
+        {
+            return "SHA224";
+        }
+        else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
+        {
+            return "SHA256";
+        }
+        else if (NISTObjectIdentifiers.id_sha384.equals(digestAlgOID))
+        {
+            return "SHA384";
+        }
+        else if (NISTObjectIdentifiers.id_sha512.equals(digestAlgOID))
+        {
+            return "SHA512";
+        }
+        else if (TeleTrusTObjectIdentifiers.ripemd128.equals(digestAlgOID))
+        {
+            return "RIPEMD128";
+        }
+        else if (TeleTrusTObjectIdentifiers.ripemd160.equals(digestAlgOID))
+        {
+            return "RIPEMD160";
+        }
+        else if (TeleTrusTObjectIdentifiers.ripemd256.equals(digestAlgOID))
+        {
+            return "RIPEMD256";
+        }
+        else if (CryptoProObjectIdentifiers.gostR3411.equals(digestAlgOID))
+        {
+            return "GOST3411";
+        }
+        else
+        {
+            return digestAlgOID.getId();            
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/spec/IEKeySpec.java b/libcore/security/src/main/java/org/bouncycastle/jce/spec/IEKeySpec.java
new file mode 100644
index 0000000..9859a22
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/spec/IEKeySpec.java
@@ -0,0 +1,70 @@
+package org.bouncycastle.jce.spec;
+
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.KeySpec;
+
+import org.bouncycastle.jce.interfaces.IESKey;
+
+/**
+ * key pair for use with an integrated encryptor - together
+ * they provide what's required to generate the message.
+ */
+public class IEKeySpec
+    implements KeySpec, IESKey
+{
+    private PublicKey   pubKey;
+    private PrivateKey  privKey;
+
+    /**
+     * @param privKey our private key.
+     * @param pubKey the public key of the sender/recipient.
+     */
+    public IEKeySpec(
+        PrivateKey  privKey,
+        PublicKey   pubKey)
+    {
+        this.privKey = privKey;
+        this.pubKey = pubKey;
+    }
+
+    /**
+     * return the intended recipient's/sender's public key.
+     */
+    public PublicKey getPublic()
+    {
+        return pubKey;
+    }
+
+    /**
+     * return the local private key.
+     */
+    public PrivateKey getPrivate()
+    {
+        return privKey;
+    }
+
+    /**
+     * return "IES"
+     */
+    public String getAlgorithm()
+    {
+        return "IES";
+    }
+
+    /**
+     * return null
+     */
+    public String getFormat()
+    {
+        return null;
+    }
+
+    /**
+     * returns null
+     */
+    public byte[] getEncoded()
+    {
+        return null;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/spec/IESParameterSpec.java b/libcore/security/src/main/java/org/bouncycastle/jce/spec/IESParameterSpec.java
new file mode 100644
index 0000000..97c7d3a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/spec/IESParameterSpec.java
@@ -0,0 +1,52 @@
+package org.bouncycastle.jce.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * Parameter spec for an integrated encryptor, as in IEEE P1363a
+ */
+public class IESParameterSpec
+    implements AlgorithmParameterSpec
+{
+    private byte[]  derivation;
+    private byte[]  encoding;
+    private int     macKeySize;
+
+    public IESParameterSpec(
+        byte[]  derivation,
+        byte[]  encoding,
+        int     macKeySize)
+    {
+        this.derivation = new byte[derivation.length];
+        System.arraycopy(derivation, 0, this.derivation, 0, derivation.length);
+
+        this.encoding = new byte[encoding.length];
+        System.arraycopy(encoding, 0, this.encoding, 0, encoding.length);
+
+        this.macKeySize = macKeySize;           
+    }
+
+    /**
+     * return the derivation vector.
+     */
+    public byte[] getDerivationV()
+    {
+        return derivation;
+    }
+
+    /**
+     * return the encoding vector.
+     */
+    public byte[] getEncodingV()
+    {
+        return encoding;
+    }
+
+    /**
+     * return the key size in bits for the MAC used with the message
+     */
+    public int getMacKeySize()
+    {
+        return macKeySize;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/openssl/PEMWriter.java b/libcore/security/src/main/java/org/bouncycastle/openssl/PEMWriter.java
new file mode 100644
index 0000000..5cbdf91
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/openssl/PEMWriter.java
@@ -0,0 +1,295 @@
+package org.bouncycastle.openssl;
+
+import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.Writer;
+import java.math.BigInteger;
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.cert.CRLException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1OutputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.cms.ContentInfo;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
+import org.bouncycastle.asn1.x509.DSAParameter;
+import org.bouncycastle.crypto.PBEParametersGenerator;
+import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.jce.PKCS10CertificationRequest;
+import org.bouncycastle.util.encoders.Base64;
+import org.bouncycastle.util.encoders.Hex;
+import org.bouncycastle.x509.X509AttributeCertificate;
+import org.bouncycastle.x509.X509V2AttributeCertificate;
+
+/**
+ * General purpose writer for OpenSSL PEM objects.
+ */
+public class PEMWriter
+    extends BufferedWriter
+{
+
+    /**
+     * Base constructor.
+     * 
+     * @param out output stream to use.
+     */
+    public PEMWriter(Writer out)
+    {
+        super(out);
+    }
+    
+    private void writeHexEncoded(byte[] bytes)
+        throws IOException
+    {
+        bytes = Hex.encode(bytes);
+        
+        for (int i = 0; i != bytes.length; i++)
+        {
+            this.write((char)bytes[i]);
+        }
+    }
+
+    private void writeEncoded(byte[] bytes) 
+        throws IOException
+    {
+        char[]  buf = new char[64];
+        
+        bytes = Base64.encode(bytes);
+        
+        for (int i = 0; i < bytes.length; i += buf.length)
+        {
+            int index = 0;
+            
+            while (index != buf.length)
+            {
+                if ((i + index) >= bytes.length)
+                {
+                    break;
+                }
+                buf[index] = (char)bytes[i + index];
+                index++;
+            }
+            this.write(buf, 0, index);
+            this.newLine();
+        }
+    }
+    
+    public void writeObject(
+        Object  o) 
+        throws IOException
+    {
+        String  type;
+        byte[]  encoding;
+        
+        if (o instanceof X509Certificate)
+        {
+            type = "CERTIFICATE";
+            try
+            {
+                encoding = ((X509Certificate)o).getEncoded();
+            }
+            catch (CertificateEncodingException e)
+            {
+                throw new IOException("Cannot encode object: " + e.toString());
+            }
+        }
+        else if (o instanceof X509CRL)
+        {
+            type = "X509 CRL";
+            try
+            {
+                encoding = ((X509CRL)o).getEncoded();
+            }
+            catch (CRLException e)
+            {
+                throw new IOException("Cannot encode object: " + e.toString());
+            }
+        }
+        else if (o instanceof KeyPair)
+        {
+            writeObject(((KeyPair)o).getPrivate());
+            return;
+        }
+        else if (o instanceof PrivateKey)
+        {
+            ByteArrayInputStream    bIn = new ByteArrayInputStream(((Key)o).getEncoded());
+            ASN1InputStream         aIn = new ASN1InputStream(bIn);
+            
+            PrivateKeyInfo          info = new PrivateKeyInfo((ASN1Sequence)aIn.readObject());
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
+            
+            if (o instanceof RSAPrivateKey)
+            {
+                type = "RSA PRIVATE KEY";
+                
+                aOut.writeObject(info.getPrivateKey());
+            }
+            else if (o instanceof DSAPrivateKey)
+            {
+                type = "DSA PRIVATE KEY";
+                
+                DSAParameter        p = DSAParameter.getInstance(info.getAlgorithmId().getParameters());
+                ASN1EncodableVector v = new ASN1EncodableVector();
+                
+                v.add(new DERInteger(0));
+                v.add(new DERInteger(p.getP()));
+                v.add(new DERInteger(p.getQ()));
+                v.add(new DERInteger(p.getG()));
+                
+                BigInteger x = ((DSAPrivateKey)o).getX();
+                BigInteger y = p.getG().modPow(x, p.getP());
+                
+                v.add(new DERInteger(y));
+                v.add(new DERInteger(x));
+                
+                aOut.writeObject(new DERSequence(v));
+            }
+            else
+            {
+                throw new IOException("Cannot identify private key");
+            }
+            
+            encoding = bOut.toByteArray();
+        }
+        else if (o instanceof PublicKey)
+        {
+            type = "PUBLIC KEY";
+            
+            encoding = ((PublicKey)o).getEncoded();
+        }
+        else if (o instanceof X509AttributeCertificate)
+        {
+            type = "ATTRIBUTE CERTIFICATE";
+            encoding = ((X509V2AttributeCertificate)o).getEncoded();
+        }
+        else if (o instanceof PKCS10CertificationRequest)
+        {
+            type = "CERTIFICATE REQUEST";
+            encoding = ((PKCS10CertificationRequest)o).getEncoded();
+        }
+        else if (o instanceof ContentInfo)
+        {
+            type = "PKCS7";
+            encoding = ((ContentInfo)o).getEncoded();
+        }
+        else
+        {
+            throw new IOException("unknown object passed - can't encode.");
+        }
+        
+        this.write("-----BEGIN " + type + "-----");
+        this.newLine();
+        
+        writeEncoded(encoding);
+        
+        this.write("-----END " + type + "-----");
+        this.newLine();
+    }
+    
+    public void writeObject(
+        Object       o,
+        String       algorithm,
+        char[]       password,
+        SecureRandom random)
+        throws IOException
+    {
+        byte[] salt = new byte[8];
+        
+        random.nextBytes(salt);
+       
+        OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator();
+        
+        pGen.init(PBEParametersGenerator.PKCS5PasswordToBytes(password), salt);
+        
+        SecretKey secretKey = null;
+        
+        if (algorithm.equalsIgnoreCase("DESEDE"))
+        {
+            // generate key
+            int keyLength = 24;
+
+            secretKey = new SecretKeySpec(((KeyParameter)pGen.generateDerivedParameters(keyLength * 8)).getKey(), algorithm);
+        }
+        else
+        {
+            throw new IOException("unknown algorithm in writeObject");
+        }
+        
+        byte[] keyData = null;
+        
+        if (o instanceof RSAPrivateCrtKey)
+        {
+            RSAPrivateCrtKey k = (RSAPrivateCrtKey)o;
+
+            RSAPrivateKeyStructure keyStruct = new RSAPrivateKeyStructure(
+                k.getModulus(),
+                k.getPublicExponent(),
+                k.getPrivateExponent(),
+                k.getPrimeP(),
+                k.getPrimeQ(),
+                k.getPrimeExponentP(),
+                k.getPrimeExponentQ(),
+                k.getCrtCoefficient());
+       
+            // convert to bytearray
+            ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+            ASN1OutputStream      aOut = new ASN1OutputStream(bOut);
+            
+            aOut.writeObject(keyStruct);
+            aOut.close();
+            
+            keyData = bOut.toByteArray();
+        }
+       
+        byte[]  encData = null;
+        
+        // cipher  
+        try
+        {
+            Cipher  c = Cipher.getInstance("DESede/CBC/PKCS5Padding", "BC");
+            c.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(salt));
+        
+            encData = c.doFinal(keyData);
+        }
+        catch (Exception e)
+        {
+            throw new IOException("exception using cipher: " + e.toString());
+        }
+       
+        // write the data
+        this.write("-----BEGIN RSA PRIVATE KEY-----");
+        this.newLine();
+        this.write("Proc-Type: 4,ENCRYPTED");
+        this.newLine();
+        this.write("DEK-Info: DES-EDE3-CBC,");
+        this.writeHexEncoded(salt);
+        this.newLine();
+        this.newLine();
+        
+        this.writeEncoded(encData);
+        this.write("-----END RSA PRIVATE KEY-----");   
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/util/Arrays.java b/libcore/security/src/main/java/org/bouncycastle/util/Arrays.java
new file mode 100644
index 0000000..c6566d3
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/util/Arrays.java
@@ -0,0 +1,67 @@
+package org.bouncycastle.util;
+
+/**
+ * General array utilities.
+ */
+public final class Arrays
+{
+    private Arrays() 
+    {
+        // static class, hide constructor
+    }
+    
+    public static boolean areEqual(
+        byte[]  a,
+        byte[]  b)
+    {
+        if (a == b)
+        {
+            return true;
+        }
+        
+        if (a.length != b.length)
+        {
+            return false;
+        }
+
+        for (int i = 0; i != a.length; i++)
+        {
+            if (a[i] != b[i])
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+    
+    public static void fill(
+        byte[] array,
+        byte value)
+    {
+        for (int i = 0; i < array.length; i++)
+        {
+            array[i] = value;
+        }
+    }
+    
+    public static void fill(
+        long[] array,
+        long value)
+    {
+        for (int i = 0; i < array.length; i++)
+        {
+            array[i] = value;
+        }
+    }
+
+    public static void fill(
+        short[] array, 
+        short value)
+    {
+        for (int i = 0; i < array.length; i++)
+        {
+            array[i] = value;
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/util/BigIntegers.java b/libcore/security/src/main/java/org/bouncycastle/util/BigIntegers.java
new file mode 100644
index 0000000..3d1c456
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/util/BigIntegers.java
@@ -0,0 +1,32 @@
+package org.bouncycastle.util;
+
+import java.math.BigInteger;
+
+/**
+ * BigInteger utilities.
+ */
+public final class BigIntegers
+{
+    /**
+     * Return the passed in value as an unsigned byte array.
+     * 
+     * @param value value to be converted.
+     * @return a byte array without a leading zero byte if present in the signed encoding.
+     */
+    public static byte[] asUnsignedByteArray(
+        BigInteger value)
+    {
+        byte[] bytes = value.toByteArray();
+        
+        if (bytes[0] == 0)
+        {
+            byte[] tmp = new byte[bytes.length - 1];
+            
+            System.arraycopy(bytes, 1, tmp, 0, tmp.length);
+            
+            return tmp;
+        }
+        
+        return bytes;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/util/Strings.java b/libcore/security/src/main/java/org/bouncycastle/util/Strings.java
new file mode 100644
index 0000000..ff42595
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/util/Strings.java
@@ -0,0 +1,191 @@
+package org.bouncycastle.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public final class Strings
+{
+    public static String fromUTF8ByteArray(byte[] bytes)
+    {
+        int i = 0;
+        int length = 0;
+
+        while (i < bytes.length)
+        {
+            length++;
+            if ((bytes[i] & 0xf0) == 0xf0)
+            {
+                // surrogate pair
+                length++;
+                i += 4;
+            }
+            else if ((bytes[i] & 0xe0) == 0xe0)
+            {
+                i += 3;
+            }
+            else if ((bytes[i] & 0xc0) == 0xc0)
+            {
+                i += 2;
+            }
+            else
+            {
+                i += 1;
+            }
+        }
+
+        char[] cs = new char[length];
+
+        i = 0;
+        length = 0;
+
+        while (i < bytes.length)
+        {
+            char ch;
+
+            if ((bytes[i] & 0xf0) == 0xf0)
+            {
+                int codePoint = ((bytes[i] & 0x0F) << 18) | ((bytes[i+1] & 0x3F) << 12) | ((bytes[i+2] & 0x3F) << 6) | (bytes[i+3] & 0x3F);
+                int U = codePoint - 0x10000;
+                char W1 = (char)(0xD800 | (U >> 10));
+                char W2 = (char)(0xDC00 | (U & 0x3FF));
+                cs[length++] = W1;
+                ch = W2;
+                i += 4;
+            }
+            else if ((bytes[i] & 0xe0) == 0xe0)
+            {
+                ch = (char)(((bytes[i] & 0x1f) << 12)
+                        | ((bytes[i + 1] & 0x3f) << 6) | (bytes[i + 2] & 0x3f));
+                i += 3;
+            }
+            else if ((bytes[i] & 0xc0) == 0xc0)
+            {
+                ch = (char)(((bytes[i] & 0x3f) << 6) | (bytes[i + 1] & 0x3f));
+                i += 2;
+            }
+            else
+            {
+                ch = (char)(bytes[i] & 0xff);
+                i += 1;
+            }
+
+            cs[length++] = ch;
+        }
+
+        return new String(cs);
+    }
+    
+    public static byte[] toUTF8ByteArray(String string)
+    {
+        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+        char[] c = string.toCharArray();
+        int i = 0;
+
+        while (i < c.length)
+        {
+            char ch = c[i];
+
+            if (ch < 0x0080)
+            {
+                bOut.write(ch);
+            }
+            else if (ch < 0x0800)
+            {
+                bOut.write(0xc0 | (ch >> 6));
+                bOut.write(0x80 | (ch & 0x3f));
+            }
+            // surrogate pair
+            else if (ch >= 0xD800 && ch <= 0xDFFF)
+            {
+                // in error - can only happen, if the Java String class has a
+                // bug.
+                if (i + 1 >= c.length)
+                {
+                    throw new IllegalStateException("invalid UTF-16 codepoint");
+                }
+                char W1 = ch;
+                ch = c[++i];
+                char W2 = ch;
+                // in error - can only happen, if the Java String class has a
+                // bug.
+                if (W1 > 0xDBFF)
+                {
+                    throw new IllegalStateException("invalid UTF-16 codepoint");
+                }
+                int codePoint = (((W1 & 0x03FF) << 10) | (W2 & 0x03FF)) + 0x10000;
+                bOut.write(0xf0 | (codePoint >> 18));
+                bOut.write(0x80 | ((codePoint >> 12) & 0x3F));
+                bOut.write(0x80 | ((codePoint >> 6) & 0x3F));
+                bOut.write(0x80 | (codePoint & 0x3F));
+            }
+            else
+            {
+                bOut.write(0xe0 | (ch >> 12));
+                bOut.write(0x80 | ((ch >> 6) & 0x3F));
+                bOut.write(0x80 | (ch & 0x3F));
+            }
+
+            i++;
+        }
+        
+        return bOut.toByteArray();
+    }
+    
+    /**
+     * A locale independent version of toUpperCase.
+     * 
+     * @param string input to be converted
+     * @return a US Ascii uppercase version
+     */
+    public static String toUpperCase(String string)
+    {
+        boolean changed = false;
+        char[] chars = string.toCharArray();
+        
+        for (int i = 0; i != chars.length; i++)
+        {
+            char ch = chars[i];
+            if ('a' <= ch && 'z' >= ch)
+            {
+                changed = true;
+                chars[i] = (char)(ch - 'a' + 'A');
+            }
+        }
+        
+        if (changed)
+        {
+            return new String(chars);
+        }
+        
+        return string;
+    }
+    
+    /**
+     * A locale independent version of toLowerCase.
+     * 
+     * @param string input to be converted
+     * @return a US ASCII lowercase version
+     */
+    public static String toLowerCase(String string)
+    {
+        boolean changed = false;
+        char[] chars = string.toCharArray();
+        
+        for (int i = 0; i != chars.length; i++)
+        {
+            char ch = chars[i];
+            if ('A' <= ch && 'Z' >= ch)
+            {
+                changed = true;
+                chars[i] = (char)(ch - 'A' + 'a');
+            }
+        }
+        
+        if (changed)
+        {
+            return new String(chars);
+        }
+        
+        return string;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/util/encoders/Base64.java b/libcore/security/src/main/java/org/bouncycastle/util/encoders/Base64.java
new file mode 100644
index 0000000..1dc94b5
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/util/encoders/Base64.java
@@ -0,0 +1,118 @@
+package org.bouncycastle.util.encoders;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class Base64
+{
+    private static final Encoder encoder = new Base64Encoder();
+    
+    /**
+     * encode the input data producing a base 64 encoded byte array.
+     *
+     * @return a byte array containing the base 64 encoded data.
+     */
+    public static byte[] encode(
+        byte[]    data)
+    {
+        ByteArrayOutputStream    bOut = new ByteArrayOutputStream();
+        
+        try
+        {
+            encoder.encode(data, 0, data.length, bOut);
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException("exception encoding base64 string: " + e);
+        }
+        
+        return bOut.toByteArray();
+    }
+
+    /**
+     * Encode the byte data to base 64 writing it to the given output stream.
+     *
+     * @return the number of bytes produced.
+     */
+    public static int encode(
+        byte[]                data,
+        OutputStream    out)
+        throws IOException
+    {
+        return encoder.encode(data, 0, data.length, out);
+    }
+    
+    /**
+     * Encode the byte data to base 64 writing it to the given output stream.
+     *
+     * @return the number of bytes produced.
+     */
+    public static int encode(
+        byte[]                data,
+        int                    off,
+        int                    length,
+        OutputStream    out)
+        throws IOException
+    {
+        return encoder.encode(data, off, length, out);
+    }
+    
+    /**
+     * decode the base 64 encoded input data. It is assumed the input data is valid.
+     *
+     * @return a byte array representing the decoded data.
+     */
+    public static byte[] decode(
+        byte[]    data)
+    {
+        ByteArrayOutputStream    bOut = new ByteArrayOutputStream();
+        
+        try
+        {
+            encoder.decode(data, 0, data.length, bOut);
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException("exception decoding base64 string: " + e);
+        }
+        
+        return bOut.toByteArray();
+    }
+    
+    /**
+     * decode the base 64 encoded String data - whitespace will be ignored.
+     *
+     * @return a byte array representing the decoded data.
+     */
+    public static byte[] decode(
+        String    data)
+    {
+        ByteArrayOutputStream    bOut = new ByteArrayOutputStream();
+        
+        try
+        {
+            encoder.decode(data, bOut);
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException("exception decoding base64 string: " + e);
+        }
+        
+        return bOut.toByteArray();
+    }
+    
+    /**
+     * decode the base 64 encoded String data writing it to the given output stream,
+     * whitespace characters will be ignored.
+     *
+     * @return the number of bytes produced.
+     */
+    public static int decode(
+        String                data,
+        OutputStream    out)
+        throws IOException
+    {
+        return encoder.decode(data, out);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java b/libcore/security/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java
new file mode 100644
index 0000000..3edc068
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java
@@ -0,0 +1,298 @@
+package org.bouncycastle.util.encoders;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class Base64Encoder
+    implements Encoder
+{
+    protected final byte[] encodingTable =
+        {
+            (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
+            (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
+            (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
+            (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
+            (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
+            (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
+            (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
+            (byte)'v',
+            (byte)'w', (byte)'x', (byte)'y', (byte)'z',
+            (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6',
+            (byte)'7', (byte)'8', (byte)'9',
+            (byte)'+', (byte)'/'
+        };
+
+    protected byte    padding = (byte)'=';
+    
+    /*
+     * set up the decoding table.
+     */
+    protected final byte[] decodingTable = new byte[128];
+
+    protected void initialiseDecodingTable()
+    {
+        for (int i = 0; i < encodingTable.length; i++)
+        {
+            decodingTable[encodingTable[i]] = (byte)i;
+        }
+    }
+    
+    public Base64Encoder()
+    {
+        initialiseDecodingTable();
+    }
+    
+    /**
+     * encode the input data producing a base 64 output stream.
+     *
+     * @return the number of bytes produced.
+     */
+    public int encode(
+        byte[]                data,
+        int                    off,
+        int                    length,
+        OutputStream    out) 
+        throws IOException
+    {
+        int modulus = length % 3;
+        int dataLength = (length - modulus);
+        int a1, a2, a3;
+        
+        for (int i = off; i < off + dataLength; i += 3)
+        {
+            a1 = data[i] & 0xff;
+            a2 = data[i + 1] & 0xff;
+            a3 = data[i + 2] & 0xff;
+
+            out.write(encodingTable[(a1 >>> 2) & 0x3f]);
+            out.write(encodingTable[((a1 << 4) | (a2 >>> 4)) & 0x3f]);
+            out.write(encodingTable[((a2 << 2) | (a3 >>> 6)) & 0x3f]);
+            out.write(encodingTable[a3 & 0x3f]);
+        }
+
+        /*
+         * process the tail end.
+         */
+        int    b1, b2, b3;
+        int    d1, d2;
+
+        switch (modulus)
+        {
+        case 0:        /* nothing left to do */
+            break;
+        case 1:
+            d1 = data[off + dataLength] & 0xff;
+            b1 = (d1 >>> 2) & 0x3f;
+            b2 = (d1 << 4) & 0x3f;
+
+            out.write(encodingTable[b1]);
+            out.write(encodingTable[b2]);
+            out.write(padding);
+            out.write(padding);
+            break;
+        case 2:
+            d1 = data[off + dataLength] & 0xff;
+            d2 = data[off + dataLength + 1] & 0xff;
+
+            b1 = (d1 >>> 2) & 0x3f;
+            b2 = ((d1 << 4) | (d2 >>> 4)) & 0x3f;
+            b3 = (d2 << 2) & 0x3f;
+
+            out.write(encodingTable[b1]);
+            out.write(encodingTable[b2]);
+            out.write(encodingTable[b3]);
+            out.write(padding);
+            break;
+        }
+
+        return (dataLength / 3) * 4 + ((modulus == 0) ? 0 : 4);
+    }
+
+    private boolean ignore(
+        char    c)
+    {
+        return (c == '\n' || c =='\r' || c == '\t' || c == ' ');
+    }
+    
+    /**
+     * decode the base 64 encoded byte data writing it to the given output stream,
+     * whitespace characters will be ignored.
+     *
+     * @return the number of bytes produced.
+     */
+    public int decode(
+        byte[]          data,
+        int             off,
+        int             length,
+        OutputStream    out)
+        throws IOException
+    {
+        byte    b1, b2, b3, b4;
+        int     outLen = 0;
+        
+        int     end = off + length;
+        
+        while (end > off)
+        {
+            if (!ignore((char)data[end - 1]))
+            {
+                break;
+            }
+            
+            end--;
+        }
+        
+        int  i = off;
+        int  finish = end - 4;
+        
+        i = nextI(data, i, finish);
+
+        while (i < finish)
+        {
+            b1 = decodingTable[data[i++]];
+            
+            i = nextI(data, i, finish);
+            
+            b2 = decodingTable[data[i++]];
+            
+            i = nextI(data, i, finish);
+            
+            b3 = decodingTable[data[i++]];
+            
+            i = nextI(data, i, finish);
+            
+            b4 = decodingTable[data[i++]];
+
+            out.write((b1 << 2) | (b2 >> 4));
+            out.write((b2 << 4) | (b3 >> 2));
+            out.write((b3 << 6) | b4);
+            
+            outLen += 3;
+            
+            i = nextI(data, i, finish);
+        }
+
+        outLen += decodeLastBlock(out, (char)data[end - 4], (char)data[end - 3], (char)data[end - 2], (char)data[end - 1]);
+        
+        return outLen;
+    }
+
+    private int nextI(byte[] data, int i, int finish)
+    {
+        while ((i < finish) && ignore((char)data[i]))
+        {
+            i++;
+        }
+        return i;
+    }
+    
+    /**
+     * decode the base 64 encoded String data writing it to the given output stream,
+     * whitespace characters will be ignored.
+     *
+     * @return the number of bytes produced.
+     */
+    public int decode(
+        String          data,
+        OutputStream    out)
+        throws IOException
+    {
+        byte    b1, b2, b3, b4;
+        int     length = 0;
+        
+        int     end = data.length();
+        
+        while (end > 0)
+        {
+            if (!ignore(data.charAt(end - 1)))
+            {
+                break;
+            }
+            
+            end--;
+        }
+        
+        int  i = 0;
+        int  finish = end - 4;
+        
+        i = nextI(data, i, finish);
+        
+        while (i < finish)
+        {
+            b1 = decodingTable[data.charAt(i++)];
+            
+            i = nextI(data, i, finish);
+            
+            b2 = decodingTable[data.charAt(i++)];
+            
+            i = nextI(data, i, finish);
+            
+            b3 = decodingTable[data.charAt(i++)];
+            
+            i = nextI(data, i, finish);
+            
+            b4 = decodingTable[data.charAt(i++)];
+
+            out.write((b1 << 2) | (b2 >> 4));
+            out.write((b2 << 4) | (b3 >> 2));
+            out.write((b3 << 6) | b4);
+            
+            length += 3;
+            
+            i = nextI(data, i, finish);
+        }
+
+        length += decodeLastBlock(out, data.charAt(end - 4), data.charAt(end - 3), data.charAt(end - 2), data.charAt(end - 1));
+
+        return length;
+    }
+
+    private int decodeLastBlock(OutputStream out, char c1, char c2, char c3, char c4) 
+        throws IOException
+    {
+        byte    b1, b2, b3, b4;
+        
+        if (c3 == padding)
+        {
+            b1 = decodingTable[c1];
+            b2 = decodingTable[c2];
+
+            out.write((b1 << 2) | (b2 >> 4));
+            
+            return 1;
+        }
+        else if (c4 == padding)
+        {
+            b1 = decodingTable[c1];
+            b2 = decodingTable[c2];
+            b3 = decodingTable[c3];
+
+            out.write((b1 << 2) | (b2 >> 4));
+            out.write((b2 << 4) | (b3 >> 2));
+            
+            return 2;
+        }
+        else
+        {
+            b1 = decodingTable[c1];
+            b2 = decodingTable[c2];
+            b3 = decodingTable[c3];
+            b4 = decodingTable[c4];
+
+            out.write((b1 << 2) | (b2 >> 4));
+            out.write((b2 << 4) | (b3 >> 2));
+            out.write((b3 << 6) | b4);
+            
+            return 3;
+        } 
+    }
+
+    private int nextI(String data, int i, int finish)
+    {
+        while ((i < finish) && ignore(data.charAt(i)))
+        {
+            i++;
+        }
+        return i;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/util/encoders/BufferedDecoder.java b/libcore/security/src/main/java/org/bouncycastle/util/encoders/BufferedDecoder.java
new file mode 100644
index 0000000..672430a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/util/encoders/BufferedDecoder.java
@@ -0,0 +1,96 @@
+package org.bouncycastle.util.encoders;
+
+
+/**
+ * a buffering class to allow translation from one format to another to
+ * be done in discrete chunks.
+ */
+public class BufferedDecoder
+{
+    protected byte[]        buf;
+    protected int           bufOff;
+
+    protected Translator    translator;
+
+    /**
+     * @param translator the translator to use.
+     * @param bufSize amount of input to buffer for each chunk.
+     */
+    public BufferedDecoder(
+        Translator  translator,
+        int         bufSize)
+    {
+        this.translator = translator;
+
+        if ((bufSize % translator.getEncodedBlockSize()) != 0)
+        {
+            throw new IllegalArgumentException("buffer size not multiple of input block size");
+        }
+
+        buf = new byte[bufSize];
+        bufOff = 0;
+    }
+
+    public int processByte(
+        byte        in,
+        byte[]      out,
+        int         outOff)
+    {
+        int         resultLen = 0;
+
+        buf[bufOff++] = in;
+
+        if (bufOff == buf.length)
+        {
+            resultLen = translator.decode(buf, 0, buf.length, out, outOff);
+            bufOff = 0;
+        }
+
+        return resultLen;
+    }
+
+    public int processBytes(
+        byte[]      in,
+        int         inOff,
+        int         len,
+        byte[]      out,
+        int         outOff)
+    {
+        if (len < 0)
+        {
+            throw new IllegalArgumentException("Can't have a negative input length!");
+        }
+
+        int resultLen = 0;
+        int gapLen = buf.length - bufOff;
+
+        if (len > gapLen)
+        {
+            System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+            resultLen += translator.decode(buf, 0, buf.length, out, outOff);
+
+            bufOff = 0;
+
+            len -= gapLen;
+            inOff += gapLen;
+            outOff += resultLen;
+
+            int chunkSize = len - (len % buf.length);
+
+            resultLen += translator.decode(in, inOff, chunkSize, out, outOff);
+
+            len -= chunkSize;
+            inOff += chunkSize;
+        }
+
+        if (len != 0)
+        {
+            System.arraycopy(in, inOff, buf, bufOff, len);
+
+            bufOff += len;
+        }
+
+        return resultLen;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/util/encoders/BufferedEncoder.java b/libcore/security/src/main/java/org/bouncycastle/util/encoders/BufferedEncoder.java
new file mode 100644
index 0000000..107eee8
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/util/encoders/BufferedEncoder.java
@@ -0,0 +1,96 @@
+package org.bouncycastle.util.encoders;
+
+
+/**
+ * a buffering class to allow translation from one format to another to
+ * be done in discrete chunks.
+ */
+public class BufferedEncoder
+{
+    protected byte[]        buf;
+    protected int           bufOff;
+
+    protected Translator    translator;
+
+    /**
+     * @param translator the translator to use.
+     * @param bufSize amount of input to buffer for each chunk.
+     */
+    public BufferedEncoder(
+        Translator  translator,
+        int         bufSize)
+    {
+        this.translator = translator;
+
+        if ((bufSize % translator.getEncodedBlockSize()) != 0)
+        {
+            throw new IllegalArgumentException("buffer size not multiple of input block size");
+        }
+
+        buf = new byte[bufSize];
+        bufOff = 0;
+    }
+
+    public int processByte(
+        byte        in,
+        byte[]      out,
+        int         outOff)
+    {
+        int         resultLen = 0;
+
+        buf[bufOff++] = in;
+
+        if (bufOff == buf.length)
+        {
+            resultLen = translator.encode(buf, 0, buf.length, out, outOff);
+            bufOff = 0;
+        }
+
+        return resultLen;
+    }
+
+    public int processBytes(
+        byte[]      in,
+        int         inOff,
+        int         len,
+        byte[]      out,
+        int         outOff)
+    {
+        if (len < 0)
+        {
+            throw new IllegalArgumentException("Can't have a negative input length!");
+        }
+
+        int resultLen = 0;
+        int gapLen = buf.length - bufOff;
+
+        if (len > gapLen)
+        {
+            System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+            resultLen += translator.encode(buf, 0, buf.length, out, outOff);
+
+            bufOff = 0;
+
+            len -= gapLen;
+            inOff += gapLen;
+            outOff += resultLen;
+
+            int chunkSize = len - (len % buf.length);
+
+            resultLen += translator.encode(in, inOff, chunkSize, out, outOff);
+
+            len -= chunkSize;
+            inOff += chunkSize;
+        }
+
+        if (len != 0)
+        {
+            System.arraycopy(in, inOff, buf, bufOff, len);
+
+            bufOff += len;
+        }
+
+        return resultLen;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/util/encoders/Encoder.java b/libcore/security/src/main/java/org/bouncycastle/util/encoders/Encoder.java
new file mode 100644
index 0000000..b066121
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/util/encoders/Encoder.java
@@ -0,0 +1,17 @@
+package org.bouncycastle.util.encoders;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Encode and decode byte arrays (typically from binary to 7-bit ASCII 
+ * encodings).
+ */
+public interface Encoder
+{
+    int encode(byte[] data, int off, int length, OutputStream out) throws IOException;
+    
+    int decode(byte[] data, int off, int length, OutputStream out) throws IOException;
+
+    int decode(String data, OutputStream out) throws IOException;
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/util/encoders/Hex.java b/libcore/security/src/main/java/org/bouncycastle/util/encoders/Hex.java
new file mode 100644
index 0000000..d69f773
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/util/encoders/Hex.java
@@ -0,0 +1,131 @@
+package org.bouncycastle.util.encoders;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class Hex
+{
+    private static final Encoder encoder = new HexEncoder();
+    
+    /**
+     * encode the input data producing a Hex encoded byte array.
+     *
+     * @return a byte array containing the Hex encoded data.
+     */
+    public static byte[] encode(
+        byte[]    data)
+    {
+        return encode(data, 0, data.length);
+    }
+    
+    /**
+     * encode the input data producing a Hex encoded byte array.
+     *
+     * @return a byte array containing the Hex encoded data.
+     */
+    public static byte[] encode(
+        byte[]    data,
+        int       off,
+        int       length)
+    {
+        ByteArrayOutputStream    bOut = new ByteArrayOutputStream();
+        
+        try
+        {
+            encoder.encode(data, off, length, bOut);
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException("exception encoding Hex string: " + e);
+        }
+        
+        return bOut.toByteArray();
+    }
+
+    /**
+     * Hex encode the byte data writing it to the given output stream.
+     *
+     * @return the number of bytes produced.
+     */
+    public static int encode(
+        byte[]         data,
+        OutputStream   out)
+        throws IOException
+    {
+        return encoder.encode(data, 0, data.length, out);
+    }
+    
+    /**
+     * Hex encode the byte data writing it to the given output stream.
+     *
+     * @return the number of bytes produced.
+     */
+    public static int encode(
+        byte[]         data,
+        int            off,
+        int            length,
+        OutputStream   out)
+        throws IOException
+    {
+        return encoder.encode(data, off, length, out);
+    }
+    
+    /**
+     * decode the Hex encoded input data. It is assumed the input data is valid.
+     *
+     * @return a byte array representing the decoded data.
+     */
+    public static byte[] decode(
+        byte[]    data)
+    {
+        ByteArrayOutputStream    bOut = new ByteArrayOutputStream();
+        
+        try
+        {
+            encoder.decode(data, 0, data.length, bOut);
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException("exception decoding Hex string: " + e);
+        }
+        
+        return bOut.toByteArray();
+    }
+    
+    /**
+     * decode the Hex encoded String data - whitespace will be ignored.
+     *
+     * @return a byte array representing the decoded data.
+     */
+    public static byte[] decode(
+        String    data)
+    {
+        ByteArrayOutputStream    bOut = new ByteArrayOutputStream();
+        
+        try
+        {
+            encoder.decode(data, bOut);
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException("exception decoding Hex string: " + e);
+        }
+        
+        return bOut.toByteArray();
+    }
+    
+    /**
+     * decode the Hex encoded String data writing it to the given output stream,
+     * whitespace characters will be ignored.
+     *
+     * @return the number of bytes produced.
+     */
+    public static int decode(
+        String          data,
+        OutputStream    out)
+        throws IOException
+    {
+        return encoder.decode(data, out);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/util/encoders/HexEncoder.java b/libcore/security/src/main/java/org/bouncycastle/util/encoders/HexEncoder.java
new file mode 100644
index 0000000..0dcae29
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/util/encoders/HexEncoder.java
@@ -0,0 +1,172 @@
+package org.bouncycastle.util.encoders;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class HexEncoder
+    implements Encoder
+{
+    protected final byte[] encodingTable =
+        {
+            (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7',
+            (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f'
+        };
+    
+    /*
+     * set up the decoding table.
+     */
+    protected final byte[] decodingTable = new byte[128];
+
+    protected void initialiseDecodingTable()
+    {
+        for (int i = 0; i < encodingTable.length; i++)
+        {
+            decodingTable[encodingTable[i]] = (byte)i;
+        }
+        
+        decodingTable['A'] = decodingTable['a'];
+        decodingTable['B'] = decodingTable['b'];
+        decodingTable['C'] = decodingTable['c'];
+        decodingTable['D'] = decodingTable['d'];
+        decodingTable['E'] = decodingTable['e'];
+        decodingTable['F'] = decodingTable['f'];
+    }
+    
+    public HexEncoder()
+    {
+        initialiseDecodingTable();
+    }
+    
+    /**
+     * encode the input data producing a Hex output stream.
+     *
+     * @return the number of bytes produced.
+     */
+    public int encode(
+        byte[]                data,
+        int                    off,
+        int                    length,
+        OutputStream    out) 
+        throws IOException
+    {        
+        for (int i = off; i < (off + length); i++)
+        {
+            int    v = data[i] & 0xff;
+
+            out.write(encodingTable[(v >>> 4)]);
+            out.write(encodingTable[v & 0xf]);
+        }
+
+        return length * 2;
+    }
+
+    private boolean ignore(
+        char    c)
+    {
+        return (c == '\n' || c =='\r' || c == '\t' || c == ' ');
+    }
+    
+    /**
+     * decode the Hex encoded byte data writing it to the given output stream,
+     * whitespace characters will be ignored.
+     *
+     * @return the number of bytes produced.
+     */
+    public int decode(
+        byte[]          data,
+        int             off,
+        int             length,
+        OutputStream    out)
+        throws IOException
+    {
+        byte    b1, b2;
+        int     outLen = 0;
+        
+        int     end = off + length;
+        
+        while (end > off)
+        {
+            if (!ignore((char)data[end - 1]))
+            {
+                break;
+            }
+            
+            end--;
+        }
+        
+        int i = off;
+        while (i < end)
+        {
+            while (i < end && ignore((char)data[i]))
+            {
+                i++;
+            }
+            
+            b1 = decodingTable[data[i++]];
+            
+            while (i < end && ignore((char)data[i]))
+            {
+                i++;
+            }
+            
+            b2 = decodingTable[data[i++]];
+
+            out.write((b1 << 4) | b2);
+            
+            outLen++;
+        }
+
+        return outLen;
+    }
+    
+    /**
+     * decode the Hex encoded String data writing it to the given output stream,
+     * whitespace characters will be ignored.
+     *
+     * @return the number of bytes produced.
+     */
+    public int decode(
+        String          data,
+        OutputStream    out)
+        throws IOException
+    {
+        byte    b1, b2;
+        int     length = 0;
+        
+        int     end = data.length();
+        
+        while (end > 0)
+        {
+            if (!ignore(data.charAt(end - 1)))
+            {
+                break;
+            }
+            
+            end--;
+        }
+        
+        int i = 0;
+        while (i < end)
+        {
+            while (i < end && ignore(data.charAt(i)))
+            {
+                i++;
+            }
+            
+            b1 = decodingTable[data.charAt(i++)];
+            
+            while (i < end && ignore(data.charAt(i)))
+            {
+                i++;
+            }
+            
+            b2 = decodingTable[data.charAt(i++)];
+
+            out.write((b1 << 4) | b2);
+            
+            length++;
+        }
+
+        return length;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/util/encoders/HexTranslator.java b/libcore/security/src/main/java/org/bouncycastle/util/encoders/HexTranslator.java
new file mode 100644
index 0000000..3fff65a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/util/encoders/HexTranslator.java
@@ -0,0 +1,87 @@
+package org.bouncycastle.util.encoders;
+
+/**
+ * Converters for going from hex to binary and back. Note: this class assumes ASCII processing.
+ */
+public class HexTranslator
+    implements Translator
+{
+    private static final byte[]   hexTable = 
+        { 
+            (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7',
+            (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f'
+        };
+
+    /**
+     * size of the output block on encoding produced by getDecodedBlockSize()
+     * bytes.
+     */
+    public int getEncodedBlockSize()
+    {
+        return 2;
+    }
+
+    public int encode(
+        byte[]  in,
+        int     inOff,
+        int     length,
+        byte[]  out,
+        int     outOff)
+    {
+        for (int i = 0, j = 0; i < length; i++, j += 2)
+        {
+            out[outOff + j] = hexTable[(in[inOff] >> 4) & 0x0f];
+            out[outOff + j + 1] = hexTable[in[inOff] & 0x0f];
+
+            inOff++;
+        }
+
+        return length * 2;
+    }
+
+    /**
+     * size of the output block on decoding produced by getEncodedBlockSize()
+     * bytes.
+     */
+    public int getDecodedBlockSize()
+    {
+        return 1;
+    }
+
+    public int decode(
+        byte[]  in,
+        int     inOff,
+        int     length,
+        byte[]  out,
+        int     outOff)
+    {
+        int halfLength = length / 2;
+        byte left, right;
+        for (int i = 0; i < halfLength; i++)
+        {
+            left  = in[inOff + i * 2];
+            right = in[inOff + i * 2 + 1];
+            
+            if (left < (byte)'a')
+            {
+                out[outOff] = (byte)((left - '0') << 4);
+            }
+            else
+            {
+                out[outOff] = (byte)((left - 'a' + 10) << 4);
+            }
+            if (right < (byte)'a')
+            {
+                out[outOff] += (byte)(right - '0');
+            }
+            else
+            {
+                out[outOff] += (byte)(right - 'a' + 10);
+            }
+
+            outOff++;
+        }
+
+        return halfLength;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/util/encoders/Translator.java b/libcore/security/src/main/java/org/bouncycastle/util/encoders/Translator.java
new file mode 100644
index 0000000..a3a0cb8
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/util/encoders/Translator.java
@@ -0,0 +1,23 @@
+package org.bouncycastle.util.encoders;
+
+/**
+ * general interface for an translator.
+ */
+public interface Translator
+{
+    /**
+     * size of the output block on encoding produced by getDecodedBlockSize()
+     * bytes.
+     */
+    public int getEncodedBlockSize();
+
+    public int encode(byte[] in, int inOff, int length, byte[] out, int outOff);
+
+    /**
+     * size of the output block on decoding produced by getEncodedBlockSize()
+     * bytes.
+     */
+    public int getDecodedBlockSize();
+
+    public int decode(byte[] in, int inOff, int length, byte[] out, int outOff);
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/util/encoders/UrlBase64.java b/libcore/security/src/main/java/org/bouncycastle/util/encoders/UrlBase64.java
new file mode 100644
index 0000000..a22d94a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/util/encoders/UrlBase64.java
@@ -0,0 +1,129 @@
+package org.bouncycastle.util.encoders;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Convert binary data to and from UrlBase64 encoding.  This is identical to
+ * Base64 encoding, except that the padding character is "." and the other 
+ * non-alphanumeric characters are "-" and "_" instead of "+" and "/".
+ * <p>
+ * The purpose of UrlBase64 encoding is to provide a compact encoding of binary
+ * data that is safe for use as an URL parameter. Base64 encoding does not
+ * produce encoded values that are safe for use in URLs, since "/" can be 
+ * interpreted as a path delimiter; "+" is the encoded form of a space; and
+ * "=" is used to separate a name from the corresponding value in an URL 
+ * parameter.
+ */
+public class UrlBase64
+{
+    private static final Encoder encoder = new UrlBase64Encoder();
+    
+    /**
+     * Encode the input data producing a URL safe base 64 encoded byte array.
+     *
+     * @return a byte array containing the URL safe base 64 encoded data.
+     */
+    public static byte[] encode(
+        byte[]    data)
+    {
+        ByteArrayOutputStream    bOut = new ByteArrayOutputStream();
+        
+        try
+        {
+            encoder.encode(data, 0, data.length, bOut);
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException("exception encoding URL safe base64 string: " + e);
+        }
+        
+        return bOut.toByteArray();
+    }
+
+    /**
+     * Encode the byte data writing it to the given output stream.
+     *
+     * @return the number of bytes produced.
+     */
+    public static int encode(
+        byte[]                data,
+        OutputStream    out)
+        throws IOException
+    {
+        return encoder.encode(data, 0, data.length, out);
+    }
+    
+    /**
+     * Decode the URL safe base 64 encoded input data - white space will be ignored.
+     *
+     * @return a byte array representing the decoded data.
+     */
+    public static byte[] decode(
+        byte[]    data)
+    {
+        ByteArrayOutputStream    bOut = new ByteArrayOutputStream();
+        
+        try
+        {
+            encoder.decode(data, 0, data.length, bOut);
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException("exception decoding URL safe base64 string: " + e);
+        }
+        
+        return bOut.toByteArray();
+    }
+    
+    /**
+     * decode the URL safe base 64 encoded byte data writing it to the given output stream,
+     * whitespace characters will be ignored.
+     *
+     * @return the number of bytes produced.
+     */
+    public static int decode(
+        byte[]                data,
+        OutputStream    out)
+        throws IOException
+    {
+        return encoder.decode(data, 0, data.length, out);
+    }
+    
+    /**
+     * decode the URL safe base 64 encoded String data - whitespace will be ignored.
+     *
+     * @return a byte array representing the decoded data.
+     */
+    public static byte[] decode(
+        String    data)
+    {
+        ByteArrayOutputStream    bOut = new ByteArrayOutputStream();
+        
+        try
+        {
+            encoder.decode(data, bOut);
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException("exception decoding URL safe base64 string: " + e);
+        }
+        
+        return bOut.toByteArray();
+    }
+    
+    /**
+     * Decode the URL safe base 64 encoded String data writing it to the given output stream,
+     * whitespace characters will be ignored.
+     *
+     * @return the number of bytes produced.
+     */
+    public static int decode(
+        String                data,
+        OutputStream    out)
+        throws IOException
+    {
+        return encoder.decode(data, out);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/util/encoders/UrlBase64Encoder.java b/libcore/security/src/main/java/org/bouncycastle/util/encoders/UrlBase64Encoder.java
new file mode 100644
index 0000000..a5fff5e
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/util/encoders/UrlBase64Encoder.java
@@ -0,0 +1,25 @@
+package org.bouncycastle.util.encoders;
+
+/**
+ * Convert binary data to and from UrlBase64 encoding.  This is identical to
+ * Base64 encoding, except that the padding character is "." and the other 
+ * non-alphanumeric characters are "-" and "_" instead of "+" and "/".
+ * <p>
+ * The purpose of UrlBase64 encoding is to provide a compact encoding of binary
+ * data that is safe for use as an URL parameter. Base64 encoding does not
+ * produce encoded values that are safe for use in URLs, since "/" can be 
+ * interpreted as a path delimiter; "+" is the encoded form of a space; and
+ * "=" is used to separate a name from the corresponding value in an URL 
+ * parameter.
+ */
+public class UrlBase64Encoder extends Base64Encoder
+{
+    public UrlBase64Encoder()
+    {
+        encodingTable[encodingTable.length - 2] = (byte) '-';
+        encodingTable[encodingTable.length - 1] = (byte) '_';
+        padding = (byte) '.';
+        // we must re-create the decoding table with the new encoded values.
+        initialiseDecodingTable();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/x509/AttributeCertificateHolder.java b/libcore/security/src/main/java/org/bouncycastle/x509/AttributeCertificateHolder.java
new file mode 100644
index 0000000..d8aa122
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/x509/AttributeCertificateHolder.java
@@ -0,0 +1,263 @@
+package org.bouncycastle.x509;
+
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.GeneralNames;
+import org.bouncycastle.asn1.x509.Holder;
+import org.bouncycastle.asn1.x509.IssuerSerial;
+import org.bouncycastle.jce.PrincipalUtil;
+import org.bouncycastle.jce.X509Principal;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+import java.security.Principal;
+import java.security.cert.CertSelector;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * The Holder object.
+ * <pre>
+ *  Holder ::= SEQUENCE {
+ *        baseCertificateID   [0] IssuerSerial OPTIONAL,
+ *                 -- the issuer and serial number of
+ *                 -- the holder's Public Key Certificate
+ *        entityName          [1] GeneralNames OPTIONAL,
+ *                 -- the name of the claimant or role
+ *        objectDigestInfo    [2] ObjectDigestInfo OPTIONAL
+ *                 -- used to directly authenticate the holder,
+ *                 -- for example, an executable
+ *  }
+ * </pre>
+ * This holder currently supports use of the baseCertificateID and the entityName.
+ */
+public class AttributeCertificateHolder 
+    implements CertSelector
+{
+    final Holder   holder;
+
+    AttributeCertificateHolder(
+        ASN1Sequence seq)
+    {
+        holder = Holder.getInstance(seq);
+    }
+
+    public AttributeCertificateHolder(
+        X509Principal issuerName,
+        BigInteger    serialNumber)
+    {
+        holder = new org.bouncycastle.asn1.x509.Holder(new IssuerSerial(
+                new GeneralNames(new DERSequence(new GeneralName(issuerName))),
+                new DERInteger(serialNumber)));        
+    }
+
+    public AttributeCertificateHolder(
+        X500Principal issuerName,
+        BigInteger    serialNumber)
+    {
+        this(X509Util.convertPrincipal(issuerName), serialNumber);
+    }
+    
+    public AttributeCertificateHolder(
+        X509Certificate cert) 
+        throws CertificateParsingException
+    {        
+        X509Principal   name;
+        
+        try
+        {
+            name = PrincipalUtil.getIssuerX509Principal(cert);
+        }
+        catch (Exception e)
+        {
+            throw new CertificateParsingException(e.getMessage());
+        }
+        
+        holder = new Holder(new IssuerSerial(generateGeneralNames(name), new DERInteger(cert.getSerialNumber())));
+    }
+    
+    public AttributeCertificateHolder(
+        X509Principal principal) 
+    {        
+        holder = new Holder(generateGeneralNames(principal));
+    }
+
+    public AttributeCertificateHolder(
+        X500Principal principal) 
+    {
+        this(X509Util.convertPrincipal(principal));
+    }
+    
+    private GeneralNames generateGeneralNames(X509Principal principal)
+    {
+        return new GeneralNames(new DERSequence(new GeneralName(principal)));
+    }
+    
+    private boolean matchesDN(X509Principal subject, GeneralNames targets)
+    {
+        GeneralName[]   names = targets.getNames();
+
+        for (int i = 0; i != names.length; i++)
+        {
+            GeneralName gn = names[i];
+
+            if (gn.getTagNo() == GeneralName.directoryName)
+            {
+                try
+                {
+                    if (new X509Principal(((ASN1Encodable)gn.getName()).getEncoded()).equals(subject))
+                    {
+                        return true;
+                    }
+                }
+                catch (IOException e)
+                {
+                }
+            }
+        }
+
+        return false;
+    }
+
+    private Object[] getNames(
+        GeneralName[] names)
+    {        
+        List        l = new ArrayList(names.length);
+        
+        for (int i = 0; i != names.length; i++)
+        {
+            if (names[i].getTagNo() == GeneralName.directoryName)
+            {
+                try
+                {
+                    l.add(new X500Principal(((ASN1Encodable)names[i].getName()).getEncoded()));
+                }
+                catch (IOException e)
+                {
+                    throw new RuntimeException("badly formed Name object");
+                }
+            }
+        }
+
+        return l.toArray(new Object[l.size()]);
+    }
+    
+    private Principal[] getPrincipals(
+        GeneralNames    names)
+    {
+        Object[]    p = this.getNames(names.getNames());
+        List        l = new ArrayList();
+        
+        for (int i = 0; i != p.length; i++)
+        {
+            if (p[i] instanceof Principal)
+            {
+                l.add(p[i]);
+            }
+        }
+        
+        return (Principal[])l.toArray(new Principal[l.size()]);
+    }
+    
+    /**
+     * Return any principal objects inside the attribute certificate holder entity names field.
+     * 
+     * @return an array of Principal objects (usually X500Principal), null if no entity names field is set.
+     */
+    public Principal[] getEntityNames()
+    {
+        if (holder.getEntityName() != null)
+        {
+            return getPrincipals(holder.getEntityName());
+        }
+        
+        return null;
+    }
+    
+    /**
+     * Return the principals associated with the issuer attached to this holder
+     * 
+     * @return an array of principals, null if no BaseCertificateID is set.
+     */
+    public Principal[] getIssuer()
+    {
+        if (holder.getBaseCertificateID() != null)
+        {
+            return getPrincipals(holder.getBaseCertificateID().getIssuer());
+        }
+        
+        return null;
+    }
+    
+    /**
+     * Return the serial number associated with the issuer attached to this holder.
+     * 
+     * @return the certificate serial number, null if no BaseCertificateID is set.
+     */
+    public BigInteger getSerialNumber()
+    {
+        if (holder.getBaseCertificateID() != null)
+        {
+            return holder.getBaseCertificateID().getSerial().getValue();
+        }
+        
+        return null;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.security.cert.CertSelector#clone()
+     */
+    public Object clone()
+    {
+        return new AttributeCertificateHolder((ASN1Sequence)holder.toASN1Object());
+    }
+
+    /* (non-Javadoc)
+     * @see java.security.cert.CertSelector#match(java.security.cert.Certificate)
+     */
+    public boolean match(Certificate cert)
+    {
+        if (!(cert instanceof X509Certificate))
+        {
+            return false;
+        }
+        
+        X509Certificate x509Cert = (X509Certificate)cert;
+        
+        try
+        {
+            if (holder.getBaseCertificateID() != null)
+            {
+                return holder.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber())
+                    && matchesDN(PrincipalUtil.getIssuerX509Principal(x509Cert), holder.getBaseCertificateID().getIssuer());
+            }
+    
+            if (holder.getEntityName() != null)
+            {
+                if (matchesDN(PrincipalUtil.getSubjectX509Principal(x509Cert), holder.getEntityName()))
+                {
+                    return true;
+                }
+            }
+        }
+        catch (CertificateEncodingException e)
+        {
+            return false;
+        }
+        
+        /**
+         * objectDigestInfo not supported
+         */
+        return false;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/x509/AttributeCertificateIssuer.java b/libcore/security/src/main/java/org/bouncycastle/x509/AttributeCertificateIssuer.java
new file mode 100644
index 0000000..0679a5c
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/x509/AttributeCertificateIssuer.java
@@ -0,0 +1,180 @@
+package org.bouncycastle.x509;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.security.cert.CertSelector;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AttCertIssuer;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.GeneralNames;
+import org.bouncycastle.asn1.x509.V2Form;
+import org.bouncycastle.asn1.x509.X509Name;
+import org.bouncycastle.jce.X509Principal;
+
+/**
+ * Carrying class for an attribute certificate issuer.
+ */
+public class AttributeCertificateIssuer
+    implements CertSelector
+{
+    final ASN1Encodable  form;
+    
+    /**
+     * @param issuer
+     */
+    AttributeCertificateIssuer(
+        AttCertIssuer issuer)
+    {
+        form = issuer.getIssuer();
+    }
+
+    public AttributeCertificateIssuer(
+        X500Principal principal) 
+        throws IOException 
+    {        
+        this(new X509Principal(principal.getEncoded()));
+    }
+    
+    public AttributeCertificateIssuer(
+        X509Principal principal) 
+    {        
+        form = new V2Form(new GeneralNames(new DERSequence(new GeneralName(principal))));
+    }
+    
+    private Object[] getNames()
+    {
+        GeneralNames    name;
+        
+        if (form instanceof V2Form)
+        {
+            name = ((V2Form)form).getIssuerName();
+        }
+        else
+        {
+            name = (GeneralNames)form;
+        }
+        
+        GeneralName[]   names = name.getNames();
+        
+        List        l = new ArrayList(names.length);
+        
+        for (int i = 0; i != names.length; i++)
+        {
+            if (names[i].getTagNo() == GeneralName.directoryName)
+            {
+                try
+                {
+                    l.add(new X500Principal(((ASN1Encodable)names[i].getName()).getEncoded()));
+                }
+                catch (IOException e)
+                {
+                    throw new RuntimeException("badly formed Name object");
+                }
+            }
+        }
+        
+        return l.toArray(new Object[l.size()]);
+    }
+    
+    /**
+     * Return any principal objects inside the attribute certificate issuer object.
+     * 
+     * @return an array of Principal objects (usually X500Principal)
+     */
+    public Principal[] getPrincipals()
+    {
+        Object[]    p = this.getNames();
+        List        l = new ArrayList();
+        
+        for (int i = 0; i != p.length; i++)
+        {
+            if (p[i] instanceof Principal)
+            {
+                l.add(p[i]);
+            }
+        }
+
+        return (Principal[])l.toArray(new Principal[l.size()]);
+    }
+    
+    private boolean matchesDN(X500Principal subject, GeneralNames targets)
+    {
+        GeneralName[]   names = targets.getNames();
+
+        for (int i = 0; i != names.length; i++)
+        {
+            GeneralName gn = names[i];
+
+            if (gn.getTagNo() == GeneralName.directoryName)
+            {
+                try
+                {
+                    if (new X500Principal(((ASN1Encodable)gn.getName()).getEncoded()).equals(subject))
+                    {
+                        return true;
+                    }
+                }
+                catch (IOException e)
+                {
+                }
+            }
+        }
+
+        return false;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.security.cert.CertSelector#clone()
+     */
+    public Object clone()
+    {
+        return new AttributeCertificateIssuer(AttCertIssuer.getInstance(form));
+    }
+    
+    /* (non-Javadoc)
+     * @see java.security.cert.CertSelector#match(java.security.cert.Certificate)
+     */
+    public boolean match(Certificate cert)
+    {
+        if (!(cert instanceof X509Certificate))
+        {
+            return false;
+        }
+        
+        X509Certificate x509Cert = (X509Certificate)cert;
+        
+        if (form instanceof V2Form)
+        {
+            V2Form issuer = (V2Form)form;
+            if (issuer.getBaseCertificateID() != null)
+            {
+                return issuer.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber())
+                    && matchesDN(x509Cert.getIssuerX500Principal(), issuer.getBaseCertificateID().getIssuer());
+            }
+            
+            GeneralNames name = issuer.getIssuerName();
+            if (matchesDN(x509Cert.getSubjectX500Principal(), name))
+            {
+                return true;
+            }
+        }
+        else
+        {
+            GeneralNames name = (GeneralNames)form;
+            if (matchesDN(x509Cert.getSubjectX500Principal(), name))
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/x509/CertPathReviewerException.java b/libcore/security/src/main/java/org/bouncycastle/x509/CertPathReviewerException.java
new file mode 100644
index 0000000..173d478
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/x509/CertPathReviewerException.java
@@ -0,0 +1,72 @@
+package org.bouncycastle.x509;
+
+import java.security.cert.CertPath;
+
+import org.bouncycastle.i18n.ErrorBundle;
+import org.bouncycastle.i18n.LocalizedException;
+
+public class CertPathReviewerException extends LocalizedException
+{
+
+    private int index = -1;
+    
+    private CertPath certPath = null;
+    
+    public CertPathReviewerException(ErrorBundle errorMessage, Throwable throwable)
+    {
+        super(errorMessage, throwable);
+    }
+
+    public CertPathReviewerException(ErrorBundle errorMessage)
+    {
+        super(errorMessage);
+    }
+
+    public CertPathReviewerException(
+            ErrorBundle errorMessage, 
+            Throwable throwable,
+            CertPath certPath,
+            int index)
+    {
+        super(errorMessage, throwable);
+        if (certPath == null || index == -1)
+        {
+            throw new IllegalArgumentException();
+        }
+        if (index < -1 || (certPath != null && index >= certPath.getCertificates().size()))
+        {
+            throw new IndexOutOfBoundsException();
+        }
+        this.certPath = certPath;
+        this.index = index;
+    }
+    
+    public CertPathReviewerException(
+            ErrorBundle errorMessage, 
+            CertPath certPath,
+            int index)
+    {
+        super(errorMessage);
+        if (certPath == null || index == -1)
+        {
+            throw new IllegalArgumentException();
+        }
+        if (index < -1 || (certPath != null && index >= certPath.getCertificates().size()))
+        {
+            throw new IndexOutOfBoundsException();
+        }
+        this.certPath = certPath;
+        this.index = index;
+    }
+    
+    public CertPath getCertPath()
+    {
+        return certPath;
+    }
+    
+    public int getIndex()
+    {
+        return index;
+    }
+
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/x509/CertPathReviewerMessages.properties b/libcore/security/src/main/java/org/bouncycastle/x509/CertPathReviewerMessages.properties
new file mode 100644
index 0000000..9df5e89
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/x509/CertPathReviewerMessages.properties
@@ -0,0 +1,563 @@
+
+## constructor exceptions 
+
+# cert path is empty
+CertPathReviewer.emptyCertPath.title = CertPath is empty
+CertPathReviewer.emptyCertPath.text = PKIXCertPathReviewer: the CertPath is empty.
+CertPathReviewer.emptyCertPath.summary = PKIXCertPathReviewer: the CertPath is empty.
+CertPathReviewer.emptyCertPath.details = PKIXCertPathReviewer: the CertPath is empty.
+
+## name constraints processing errors
+
+# cert DN is not in the permitted tree
+# {0} DN as String 
+CertPathReviewer.notPermittedDN.title = Name constraint error: certificate DN is not permitted
+CertPathReviewer.notPermittedDN.text = Name constraint error: the certificate DN {0} is not permitted.
+CertPathReviewer.notPermittedDN.summary = Name constraint error: certificate DN is not permitted.
+CertPathReviewer.notPermittedDN.details = Name constraint checking error. The certificate DN {0} is not in the permitted set of DNs.
+
+# cert DN is in the excluded tree
+# {0} DN as String
+CertPathReviewer.excludedDN.title = Name constraint error: certificate DN is excluded
+CertPathReviewer.excludedDN.text = Name constraint error: The certificate DN {0} is excluded.
+CertPathReviewer.excludedDN.summary = Name constraint error: certificate DN is excluded.
+CertPathReviewer.excludedDN.details = Name constraint checking error. The certificate DN {0} is inside of the excluded set of DNs.
+
+# cert email is not in the permitted tree
+# {0} email address as String
+CertPathReviewer.notPermittedEmail.title = Name constraint error: not permitted email address
+CertPathReviewer.notPermittedEmail.text = Name constraint error: certificate contains the not permitted email address {0}.
+CertPathReviewer.notPermittedEmail.summary = Name constraint error: not permitted email address.
+CertPathReviewer.notPermittedEmail.details = Name constraint checking error. The certificate contains the email address {0} which is not in the permitted set of email addresses.
+
+# cert email is in the excluded tree
+# {0} email as String
+CertPathReviewer.excludedEmail.title = Name constraint error: excluded email address
+CertPathReviewer.excludedEmail.text = Name constraint error: certificate contains the excluded email address {0}. 
+CertPathReviewer.excludedEmail.summary = Name constraint error: excluded email address.
+CertPathReviewer.excludedEmail.details = Name constraint checking error. The certificate contains the email address {0} which is in the excluded set of email addresses.
+
+# cert IP is not in the permitted tree
+# {0} ip address as String
+CertPathReviewer.notPermittedIP.title = Name constraint error: not permitted IP address
+CertPathReviewer.notPermittedIP.text = Name constraint error: certificate contains the not permitted IP address {0}.
+CertPathReviewer.notPermittedIP.summary = Name constraint error: not permitted IP address.
+CertPathReviewer.notPermittedIP.details = Name constraint checking error. The certificate contains the IP address {0} which is not in the permitted set of IP addresses.
+
+# cert ip is in the excluded tree
+# {0} ip address as String
+CertPathReviewer.excludedIP.title = Name constraint error: excluded IP address
+CertPathReviewer.excludedIP.text = Name constraint error: certificate contains the excluded IP address {0}.
+CertPathReviewer.excludedIP.summary = Name constraint error: excluded IP address.
+CertPathReviewer.excludedIP.details = Name constraint checking error. The certificate contains the IP address {0} which is in the excluded set of IP addresses.
+
+# error processing the name constraints extension
+CertPathReviewer.ncExtError.title = Name constraint checking failed
+CertPathReviewer.ncExtError.text = Name constraint checking failed: there was an error processing the name constraints extension of the certificate.
+CertPathReviewer.ncExtError.summary = Error processing the name constraints extension.
+CertPathReviewer.ncExtError.details = Name constraint checking failed: there was an error processing the name constraints extension of the certificate.
+
+# error processing the subject alternative name extension
+CertPathReviewer.subjAltNameExtError.title = Name constraint checking failed
+CertPathReviewer.subjAltNameExtError.text = Name constraint checking failed: there was an error processing the subject alernative name extension of the certificate.
+CertPathReviewer.subjAltNameExtError.summary = Error processing the subject alternative name extension.
+CertPathReviewer.subjAltNameExtError.details = Name constraint checking failed: there was an error processing the subject alternative name extension of the certificate.
+
+# exception extracting subject name when checking subtrees
+# {0} subject Principal
+CertPathReviewer.ncSubjectNameError.title = Name constraint checking failed
+CertPathReviewer.ncSubjectNameError.text = Name constraint checking failed: there was an exception extracting the DN from the certificate.
+CertPathReviewer.ncSubjectNameError.summary = Name constraint checking failed: exception extracting the DN.
+CertPathReviewer.ncSubjectNameError.details = Name constraint checking failed: there was an exception extracting the DN from the certificate.
+
+
+## path length errors
+
+# max path length extended
+CertPathReviewer.pathLenghtExtended.title = Maximum path length extended 
+CertPathReviewer.pathLenghtExtended.text = Certificate path invalid: Maximum path length extended.
+CertPathReviewer.pathLenghtExtended.summary = Certificate path invalid: Maximum path length extended.
+CertPathReviewer.pathLenghtExtended.details = Certificate path invalid: Maximum path length extended.
+
+# error reading length constraint from basic constraint extension
+CertPathReviewer.processLengthConstError.title = Path length checking failed
+CertPathReviewer.processLengthConstError.text = Path length checking failed: there was an error processing the basic constraint extension of the certificate. 
+CertPathReviewer.processLengthConstError.summary = Error processing the subject alternative name extension.
+CertPathReviewer.processLengthConstError.details = Path length checking failed: there was an error processing the basic constraint extension of the certificate.
+
+
+## path length notifications
+
+# total path length as defined in rfc 3280
+# {0} the path length as Integer
+CertPathReviewer.totalPathLength.title = Total path length
+CertPathReviewer.totalPathLength.text = The total path length without self-signed certificates is {0}.
+CertPathReviewer.totalPathLength.summary = The total path length without self-signed certificates is {0}.
+CertPathReviewer.totalPathLength.details = The total path length without self-signed certificates, as defined in RFC 3280, is {0}.
+
+
+## critical extensions errors
+
+# one unknown critical extension
+# {0} extension as String
+CertPathReviewer.unknownCriticalExt.title = Unknown critical extension
+CertPathReviewer.unknownCriticalExt.text = The certificate contains the unknown critical extension {0}.
+CertPathReviewer.unknownCriticalExt.summary = Unknown critical extension: {0}.
+CertPathReviewer.unknownCriticalExt.details = The certificate contains the unknown critical extension with the OID {0}.
+
+# more unknown critical extensions
+# {0} extensions as Set of Strings
+CertPathReviewer.unknownCriticalExts.title = Unknown critical extensions
+CertPathReviewer.unknownCriticalExts.text = The certificate contains two or more unknown critical extensions: {0}.
+CertPathReviewer.unknownCriticalExts.summary = Unknown critical extensions: {0}.
+CertPathReviewer.unknownCriticalExts.details = The certificate contains two or more unknown critical extensions with the OIDs: {0}.
+
+# error processing critical extension
+# {0} the message of the underlying exception
+# {1} the underlying exception
+CertPathReviewer.criticalExtensionError.title = Error processing a critical extension
+CertPathReviewer.criticalExtensionError.text = Error processing a critical extension. Cause: {0}.
+CertPathReviewer.criticalExtensionError.summary = Error processing a critical extension. Cause: {0}.
+CertPathReviewer.criticalExtensionError.details = Error processing a critical extension. Cause: {0}.
+
+# error initializing the certpath checkers
+# {0} the message of the underlying exception
+# {1} the underlying exception
+CertPathReviewer.certPathCheckerError.title = Checking critical extensions failed
+CertPathReviewer.certPathCheckerError.text = Checking critical extensions failed: there was an error initializing a CertPathChecker.
+CertPathReviewer.certPathCheckerError.summary = Checking critical extensions failed: error initializing a CertPathChecker
+CertPathReviewer.certPathCheckerError.details = Checking critical extensions failed: there was an error initializing a CertPathChecker. Cause: {0}
+
+
+## check signature errors
+
+# trustanchor found, but certificate validation failed
+CertPathReviewer.trustButInvalidCert.title = TrustAnchor found, but certificate invalid
+CertPathReviewer.trustButInvalidCert.text = A TrustAnchor was found but the certificate validation failed.
+CertPathReviewer.trustButInvalidCert.summary = TrustAnchor found but certificate validation failed.
+CertPathReviewer.trustButInvalidCert.details = A TrustAnchor was found but the certificate validation failed.
+
+# trustanchor - cannot extract issuer
+CertPathReviewer.trustAnchorIssuerError.title = Finding TrustAnchor failed 
+CertPathReviewer.trustAnchorIssuerError.text = Finding TrustAnchor failed: cannot extract issuer from certificate.
+CertPathReviewer.trustAnchorIssuerError.summary = Finding TrustAnchor failed: cannot extract issuer from certificate.
+CertPathReviewer.trustAnchorIssuerError.details = Finding TrustAnchor failed: cannot extract issuer from certificate.
+
+# no trustanchor was found for the certificate path
+# {0} issuer of the root certificate of the path
+# {1} number of trusted root certificates (trustanchors) provided
+CertPathReviewer.noTrustAnchorFound.title = No trusted root certificate found
+CertPathReviewer.noTrustAnchorFound.text = The root certificate of the certificate path was issued by a CA that is not in the the trusted-root-certificate-store used for the path validation. The name of the CA is "{0}".
+CertPathReviewer.noTrustAnchorFound.summary = The root certificate of the certificate path was issued by a CA that is not in the the trusted-root-certificate-store used for the path validation.
+CertPathReviewer.noTrustAnchorFound.details = The root certificate of the certificate path was issued by a CA that is not in the the trusted-root-certificate-store used for the path validation. The name of the CA is "{0}". The trusted-root-certificate store contains {1} CA(s).
+
+# conflicting trust anchors
+# {0} number of trustanchors found (Integer)
+# {1} the ca name
+CertPathReviewer.conflictingTrustAnchors.title = Corrupt trust root store
+CertPathReviewer.conflictingTrustAnchors.text = Warning: corrupt trust root store: There are {0} trusted public keys for the CA "{1}" - please ensure with CA which is the correct key.
+CertPathReviewer.conflictingTrustAnchors.summary = Warning: corrupt trust root store: There are {0} trusted public keys for the CA "{1}" - please ensure with CA which is the correct key.
+CertPathReviewer.conflictingTrustAnchors.details = Warning: corrupt trust root store: There are {0} trusted public keys for the CA "{1}" - please ensure with CA which is the correct key.
+
+# trustanchor DN is invalid
+# {0} DN of the Trustanchor
+CertPathReviewer.trustDNInvalid.title = DN of TrustAnchor is improperly specified
+CertPathReviewer.trustDNInvalid.text = The DN of the TrustAnchor is improperly specified: {0}.
+CertPathReviewer.trustDNInvalid.summary = The DN of the TrustAnchor is improperly specified.
+CertPathReviewer.trustDNInvalid.details = The DN of the TrustAnchor is improperly specified: {0}. It's not a valid X.500 name. See RFC 1779 or RFC 2253. 
+
+# trustanchor public key algorithm error
+CertPathReviewer.trustPubKeyError.title = Error processing public key of the trust anchor
+CertPathReviewer.trustPubKeyError.text = Error processing public key of the trust anchor.
+CertPathReviewer.trustPubKeyError.summary = Error processing public key of the trust anchor.
+CertPathReviewer.trustPubKeyError.details = Error processing public key of the trust anchor. Could not extract the AlorithmIdentifier for the key.
+
+# can not verifiy signature: issuer public key unknown
+CertPathReviewer.NoIssuerPublicKey.title = Can not verify the certificate signature 
+CertPathReviewer.NoIssuerPublicKey.text = Can not verify the certificate signature: Issuer public key is unknown.
+CertPathReviewer.NoIssuerPublicKey.summary = Can not verify the certificate signature: Issuer public key is unknown.
+CertPathReviewer.NoIssuerPublicKey.details = Can not verify the certificate signature: Issuer public key is unknown.
+
+# signature can not be verified
+# {0} message of the underlying exception (english)
+# {1} the underlying exception
+CertPathReviewer.signatureNotVerified.title = Certificate signature invalid
+CertPathReviewer.signatureNotVerified.text = The certificate signature is invalid.
+CertPathReviewer.signatureNotVerified.summary = The certificate signature is invalid.
+CertPathReviewer.signatureNotVerified.details = The certificate signature is invalid. Cause: {0}
+
+# certificate expired
+# {0} the date the certificate expired 
+CertPathReviewer.certificateExpired.title = Certificate is expired
+CertPathReviewer.certificateExpired.text = Could not validate the certificate. Certificate expired on {0,date} {0,time,full}.
+CertPathReviewer.certificateExpired.summary = Certificate expired on {0,date} {0,time,full}.
+CertPathReviewer.certificateExpired.details = Could not validate the certificate. Certificate expired on {0,date} {0,time,full}. 
+
+# certificate not yet valid
+# {0} the date from which on the certificate is valid
+CertPathReviewer.certificateNotYetValid.title = Certificate is not yet valid
+CertPathReviewer.certificateNotYetValid.text = Could not validate the certificate. Certificate is not valid untill {0,date} {0,time,full}.
+CertPathReviewer.certificateNotYetValid.summary = Certificate is not valid untill {0,date} {0,time,full}.
+CertPathReviewer.certificateNotYetValid.details = Could not validate the certificate. Certificate is not valid untill {0,date} {0,time,full}. 
+
+# certificate invalid issuer DN
+# {0} expected issuer DN as String
+# {1} found issuer DN as String
+CertPathReviewer.certWrongIssuer.title = Issuer of certificate not valid
+CertPathReviewer.certWrongIssuer.text = Issuer of certificate is not valid. Expected {0}, but found {1}. 
+CertPathReviewer.certWrongIssuer.summary = Issuer of certificate is not valid. 
+CertPathReviewer.certWrongIssuer.details = Issuer of certificate is not valid. Expected {0}, but found {1}.
+
+# intermediate certificate is no ca cert
+CertPathReviewer.noCACert.title = Certificate is no CA certificate
+CertPathReviewer.noCACert.text = Intermediate certificate is no CA certificate.
+CertPathReviewer.noCACert.summary = The certificate is no CA certificate.
+CertPathReviewer.noCACert.details = The certificate is no CA certificate but used as one.
+
+# cert laks basic constraints
+CertPathReviewer.noBasicConstraints.title = Certificate has no basic constraints
+CertPathReviewer.noBasicConstraints.text = Intermediate certificate has no basic constraints.
+CertPathReviewer.noBasicConstraints.summary = Intermediate certificate has no basic constraints.
+CertPathReviewer.noBasicConstraints.details = Intermediate certificate has no basic constraints.
+
+# error processing basic constraints
+CertPathReviewer.errorProcesingBC.title = Error processing the basic constraints extension
+CertPathReviewer.errorProcesingBC.text = There was an error while processing the basic constraints extension of this certificate.
+CertPathReviewer.errorProcesingBC.summary = Error processing the basic constraints extension. 
+CertPathReviewer.errorProcesingBC.details = There was an error while processing the basic constraints extension of this certificate.
+
+# certificate not usable for signing certs
+CertPathReviewer.noCertSign.title = Key not usable for signing certificates
+CertPathReviewer.noCertSign.text = The key usage constraint does not allow the use of this certificate key for signing certificates.
+CertPathReviewer.noCertSign.summary = The certificate key can not be used for signing certificates.
+CertPathReviewer.noCertSign.details = The key usage constraint does not allow the use of this certificate key for signing certificates.
+
+# error processing public key
+CertPathReviewer.pubKeyError.title = Error processing public key
+CertPathReviewer.pubKeyError.text = Error processing public key of the certificate.
+CertPathReviewer.pubKeyError.summary = Error processing public key of the certificate.
+CertPathReviewer.pubKeyError.details = Error processing public key of the certificate. Could not extract the AlorithmIdentifier for the key.
+
+
+## check signatures notifications
+
+# certificate path validation date
+# {0} date for which the cert path is validated
+# {1} current date
+CertPathReviewer.certPathValidDate.title = Certificate path validation date
+CertPathReviewer.certPathValidDate.text = The certificate path was applied on {0,date} {0,time,full}. It was validated at {1,date} {1,time,full}.
+CertPathReviewer.certPathValidDate.summary = The certificate path was validated for {0,date} {0,time,full}. It was validated at {1,date} {1,time,full}.
+CertPathReviewer.certPathValidDate.details = The certificate path was validated for {0,date} {0,time,full}. It was validated at {1,date} {1,time,full}.
+
+
+## check policy errors
+
+# error processing certificate policy extension
+CertPathReviewer.policyExtError.title = Policy checking failed
+CertPathReviewer.policyExtError.text = Policy checking failed: there was an error processing the certificate policy extension. 
+CertPathReviewer.policyExtError.summary = Error processing the certificate policy extension.
+CertPathReviewer.policyExtError.details = Policy checking failed: there was an error processing the certificate policy extension. 
+
+# error processing policy constraints extension
+CertPathReviewer.policyConstExtError.title = Policy checking failed
+CertPathReviewer.policyConstExtError.text = Policy checking failed: there was an error processing the policy constraints extension.
+CertPathReviewer.policyConstExtError.summary = Error processing the policy constraints extension.
+CertPathReviewer.policyConstExtError.details = Policy checking failed: there was an error processing the policy constraints extension.
+
+# error processing policy mapping extension
+CertPathReviewer.policyMapExtError.title = Policy checking failed
+CertPathReviewer.policyMapExtError.text = Policy checking failed: there was an error processing the policy mapping extension.
+CertPathReviewer.policyMapExtError.summary = Error processing the policy mapping extension.
+CertPathReviewer.policyMapExtError.details = Policy checking failed: there was an error processing the policy mapping extension.
+
+# error processing inhibit any policy extension
+CertPathReviewer.policyInhibitExtError.title = Policy checking failed
+CertPathReviewer.policyInhibitExtError.text = Policy checking failed: there was an error processing the policy mapping extension.
+CertPathReviewer.policyInhibitExtError.summary = Error processing the inhibit any policy extension.
+CertPathReviewer.policyInhibitExtError.details = Policy checking failed: there was an error processing the policy mapping extension.
+
+# error building qualifier set
+CertPathReviewer.policyQualifierError.title = Policy checking failed
+CertPathReviewer.policyQualifierError.text = Policy checking failed: error building the policy qualifier set.
+CertPathReviewer.policyQualifierError.summary = Policy checking failed: error building the policy qualifier set.
+CertPathReviewer.policyQualifierError.details = Policy checking failed: error building the policy qualifier set.
+
+# no valid policy tree - explicit policy required
+CertPathReviewer.noValidPolicyTree.title = Policy checking failed
+CertPathReviewer.noValidPolicyTree.text = Policy checking failed: no valid policy tree found when one expected.
+CertPathReviewer.noValidPolicyTree.summary = Policy checking failed: no valid policy tree found when one expected.
+CertPathReviewer.noValidPolicyTree.details = Policy checking failed: no valid policy tree found when one expected.
+
+# expicit policy requested, but no policy available
+CertPathReviewer.explicitPolicy.title = Policy checking failed
+CertPathReviewer.explicitPolicy.text = Policy checking failed: explicit policy requested but no policy available.
+CertPathReviewer.explicitPolicy.summary = Policy checking failed: explicit policy requested but no policy available.
+CertPathReviewer.explicitPolicy.details = Policy checking failed: explicit policy requested but no policy available.
+
+# path processing failed on policy
+CertPathReviewer.invalidPolicy.title = Path processing failed on policy
+CertPathReviewer.invalidPolicy.text = Path processing failed on policy.
+CertPathReviewer.invalidPolicy.summary = Path processing failed on policy.
+CertPathReviewer.invalidPolicy.details = Path processing failed on policy.
+
+# invalid policy mapping
+CertPathReviewer.invalidPolicyMapping.title = Invalid policy mapping 
+CertPathReviewer.invalidPolicyMapping.text = Certificate contains an invalid policy mapping.
+CertPathReviewer.invalidPolicyMapping.summary = Certificate contains an invalid policy mapping. 
+CertPathReviewer.invalidPolicyMapping.details = Certificate contains a policy mapping including the value any policy which is invalid.
+
+## check CRL notifications
+
+# found local valid CRL
+# {0} thisUpdate of the CRL
+# {1} nextUpdate of the CRL
+CertPathReviewer.localValidCRL.title = Found valid local CRL
+CertPathReviewer.localValidCRL.text = Found a valid CRL in local certstore. Issued on {0,date}, next update {1,date}.
+CertPathReviewer.localValidCRL.summary = Found a valid CRL in local certstore. Issued on {0,date}, next update {1,date}.
+CertPathReviewer.localValidCRL.details = Found a valid CRL in local certstore. Issued on {0,date}, next update {1,date}.
+
+
+# found matching CRL, but not valid
+# {0} thisUpdate of the CRL
+# {1} nextUpdate of the CRL
+CertPathReviewer.localInvalidCRL.title = Local CRL outdated
+CertPathReviewer.localInvalidCRL.text = Did not use a matching CRL in a local certstore, because it is outdated. Issued on {0,date}, next update {1,date}.
+CertPathReviewer.localInvalidCRL.summary = Did not use a matching CRL in a local certstore, because it is outdated. Issued on {0,date}, next update {1,date}.
+CertPathReviewer.localInvalidCRL.details = Did not use a matching CRL in a local certstore, because it is outdated. Issued on {0,date}, next update {1,date}.
+
+# found a valid crl at crl distribution point
+# {0} thisUpdate of the CRL
+# {1} nextUpdate of the CRL
+# {2} the url of the distribution point
+CertPathReviewer.onlineValidCRL.title = Found valid CRL at CRL distribution point
+CertPathReviewer.onlineValidCRL.text = Found a valid CRL at: {2}. Issued on {0,date}, next update on {1,date}.
+CertPathReviewer.onlineValidCRL.summary = Found a valid CRL at: {2}. Issued on {0,date}, next update on {1,date}.
+CertPathReviewer.onlineValidCRL.details = Found a valid CRL at: {2}. Issued on {0,date}, next update on {1,date}.
+
+# found an invalid CRL at crl distribution point
+# {0} thisUpdate of the CRL
+# {1} nextUpdate of the CRL
+# {2} the url of the distribution point
+CertPathReviewer.onlineInvalidCRL.title = Outdated CRL at CRL distribution point
+CertPathReviewer.onlineInvalidCRL.text = The CRL loaded from {2} was outdated. Issued on {0,date}, next update on {1,date}.
+CertPathReviewer.onlineInvalidCRL.summary = The CRL loaded from {2} was outdated. Issued on {0,date}, next update on {1,date}.
+CertPathReviewer.onlineInvalidCRL.details = The CRL loaded from {2} was outdated. Issued on {0,date}, next update on {1,date}.
+
+# Certificate not revoked
+CertPathReviewer.notRevoked.title = Certificate not revoked
+CertPathReviewer.notRevoked.text = The certificate was not revoked.
+CertPathReviewer.notRevoked.summary = The certificate was not revoked.
+CertPathReviewer.notRevoked.details = The certificate was not revoked.
+
+# CRL found: certificate was revoked, but after the validationDate
+# {0} the date the certificate was revoked
+# {1} the reason for revoking the certificate
+CertPathReviewer.revokedAfterValidation.title = Certificate was revoked after the validation date
+CertPathReviewer.revokedAfterValidation.text = The certificate was revoked after the validation date at {0,date} {0,time,full}. Reason: {1}.
+CertPathReviewer.revokedAfterValidation.summary = The certificate was revoked after the validation date at {0,date} {0,time,full}.
+CertPathReviewer.revokedAfterValidation.details = The certificate was revoked after the validation date at {0,date} {0,time,full}. Reason: {1}.
+
+# updated crl available
+# {0} date since when the update is available
+CertPathReviewer.crlUpdateAvailable.title = CRL update available
+CertPathReviewer.crlUpdateAvailable.text = An update for the CRL of this certificate is available since {0,date} {0,time,full}.
+CertPathReviewer.crlUpdateAvailable.summary = An update for the CRL of this certificate is available since {0,date} {0,time,full}.
+CertPathReviewer.crlUpdateAvailable.details = An update for the CRL of this certificate is available since {0,date} {0,time,full}.
+
+# crl distribution point url
+# {0} the crl distribution point url as String
+CertPathReviewer.crlDistPoint.title = CRL distribution point
+CertPathReviewer.crlDistPoint.text = A CRL can be obtained from: {0}.
+CertPathReviewer.crlDistPoint.summary = A CRL can be obtained from: {0}.
+CertPathReviewer.crlDistPoint.details = A CRL can be obtained from: {0}.
+
+# ocsp location
+# {0} the url on which the ocsp service can be found
+CertPathReviewer.ocspLocation.title = OCSP responder location
+CertPathReviewer.ocspLocation.text = OCSP responder location: {0}.
+CertPathReviewer.ocspLocation.summary = OCSP responder location: {0}.
+CertPathReviewer.ocspLocation.details = OCSP responder location: {0}.
+
+# unable to get crl from crl distribution point
+# {0} the url of the distribution point
+# {1} the message of the occured exception
+# {2} the occured exception
+CertPathReviewer.loadCrlDistPointError.title = Cannot load CRL from CRL distribution point
+CertPathReviewer.loadCrlDistPointError.text = Unable to load a CRL from: {0}. An Exception occured.
+CertPathReviewer.loadCrlDistPointError.summary = Unable to load a CRL from: {0}. An Exception occured.
+CertPathReviewer.loadCrlDistPointError.details = Unable to load a CRL from: {0}. An Exception occured: Cause: {1}.
+
+# no crl found in certstores
+# {0} the issuers which we searched for
+# {1} list of crl issuer names that are found in the certstores
+# {2} number of crls in the certstores
+CertPathReviewer.noCrlInCertstore.title = No matching CRL found in local certstores
+CertPathReviewer.noCrlInCertstore.text = No matching CRL was found in the provided local certstore.
+CertPathReviewer.noCrlInCertstore.summary = No matching CRL was found in the provided local certstore.
+CertPathReviewer.noCrlInCertstore.details = No matching CRL was found in the provided local certstore. \
+No CRL was found for the selector "{0}". The {2} CRL(s) in the certstores are from "{1}".
+
+
+## check CRL exceptions
+
+# cannot extract issuer from certificate
+CertPathReviewer.crlIssuerException.title = CRL checking failed
+CertPathReviewer.crlIssuerException.text = CRL checking failed: cannot extract issuer from certificate.
+CertPathReviewer.crlIssuerException.summary = CRL checking failed: cannot extract issuer from certificate.
+CertPathReviewer.crlIssuerException.details = CRL checking failed: cannot extract issuer from certificate.
+
+# cannot extract crls
+# {0} message from the underlying exception
+# {1} the underlying exception
+CertPathReviewer.crlExtractionError.title = CRL checking failed
+CertPathReviewer.crlExtractionError.text = CRL checking failed: Cannot extract CRL from CertStore.
+CertPathReviewer.crlExtractionError.summary = CRL checking failed: Cannot extract CRL from CertStore.
+CertPathReviewer.crlExtractionError.details = CRL checking failed: Cannot extract CRL from CertStore. Cause: {0}.
+
+# Issuer certificate key usage extension does not permit crl signing
+CertPathReviewer.noCrlSigningPermited.title = CRL checking failed
+CertPathReviewer.noCrlSigningPermited.text = CRL checking failed: issuer certificate does not permit CRL signing.
+CertPathReviewer.noCrlSigningPermited.summary = CRL checking failed: issuer certificate does not permit CRL signing.
+CertPathReviewer.noCrlSigningPermited.details = CRL checking failed: issuer certificate does not permit CRL signing.
+
+# can not verify crl: issuer public key unknown
+CertPathReviewer.crlNoIssuerPublicKey.title = CRL checking failed
+CertPathReviewer.crlNoIssuerPublicKey.text = CRL checking failed: Can not verify the CRL: Issuer public key is unknown.
+CertPathReviewer.crlNoIssuerPublicKey.summary = CRL checking failed: Can not verify the CRL: Issuer public key is unknown.
+CertPathReviewer.crlNoIssuerPublicKey.details = CRL checking failed: Can not verify the CRL: Issuer public key is unknown.
+
+# crl verification failed
+CertPathReviewer.crlVerifyFailed.title = CRL checking failed
+CertPathReviewer.crlVerifyFailed.text = CRL checking failed: CRL signature is invalid.
+CertPathReviewer.crlVerifyFailed.summary = CRL checking failed: CRL signature is invalid.
+CertPathReviewer.crlVerifyFailed.details = CRL checking failed: CRL signature is invalid.
+
+# no valid CRL found
+CertPathReviewer.noValidCrlFound.title = CRL checking failed
+CertPathReviewer.noValidCrlFound.text = CRL checking failed: no valid CRL found.
+CertPathReviewer.noValidCrlFound.summary = CRL checking failed: no valid CRL found.
+CertPathReviewer.noValidCrlFound.details = CRL checking failed: no valid CRL found.
+
+# No base CRL for delta CRL
+CertPathReviewer.noBaseCRL.title = CRL checking failed
+CertPathReviewer.noBaseCRL.text = CRL checking failed: no base CRL found for delta CRL.
+CertPathReviewer.noBaseCRL.summary = CRL checking failed: no base CRL found for delta CRL.
+CertPathReviewer.noBaseCRL.details = CRL checking failed: no base CRL found for delta CRL.
+
+# certificate revoked
+# {0} the date the certificate was revoked
+# {1} the reason for revoking the certificate
+CertPathReviewer.certRevoked.title = Certificate was revoked
+CertPathReviewer.certRevoked.text = The certificate is invalid, because it was revoked at {0,date} {0,time,full}. Reason: {1}.
+CertPathReviewer.certRevoked.summary = The certificate is invalid, because it was revoked at {0,date} {0,time,full}.
+CertPathReviewer.certRevoked.details = The certificate is invalid, because it was revoked at {0,date} {0,time,full}. Reason: {1}.
+
+# error processing issuing distribution point extension
+CertPathReviewer.distrPtExtError.title = CRL checking failed
+CertPathReviewer.distrPtExtError.text = CRL checking failed: there was an error processing the issuing distribution point extension. 
+CertPathReviewer.distrPtExtError.summary = Error processing the issuing distribution point extension.
+CertPathReviewer.distrPtExtError.details = CRL checking failed: there was an error processing the issuing distribution point extension.
+
+# error processing crl distribution points extension
+CertPathReviewer.crlDistPtExtError.title = CRL checking failed
+CertPathReviewer.crlDistPtExtError.text = CRL checking failed: there was an error processing the crl distribution points extension.
+CertPathReviewer.crlDistPtExtError.summary = Error processing the crl distribution points extension.
+CertPathReviewer.crlDistPtExtError.details = CRL checking failed: there was an error processing the crl distribution points extension.
+
+# error processing the authority info access extension
+CertPathReviewer.crlAuthInfoAccError.title = CRL checking failed
+CertPathReviewer.crlAuthInfoAccError.text = CRL checking failed: there was an error processing the authority info access extension.
+CertPathReviewer.crlAuthInfoAccError.summary = Error processing the authority info access extension.
+CertPathReviewer.crlAuthInfoAccError.details = CRL checking failed: there was an error processing the authority info access extension.
+
+# error processing delta crl indicator extension
+CertPathReviewer.deltaCrlExtError.title = CRL checking failed
+CertPathReviewer.deltaCrlExtError.text = CRL checking failed: there was an error processing the delta CRL indicator extension. 
+CertPathReviewer.deltaCrlExtError.summary = Error processing the delta CRL indicator extension.
+CertPathReviewer.deltaCrlExtError.details = CRL checking failed: there was an error processing the delta CRL indicator extension.
+
+# error porcessing crl number extension
+CertPathReviewer.crlNbrExtError.title = CRL checking failed
+CertPathReviewer.crlNbrExtError.text = CRL checking failed: there was an error processing the CRL number extension.
+CertPathReviewer.crlNbrExtError.summary = Error processing the CRL number extension.
+CertPathReviewer.crlNbrExtError.details = CRL checking failed: there was an error processing the CRL number extension.
+
+# error processing crl reason code extension
+CertPathReviewer.crlReasonExtError.title = CRL checking failed
+CertPathReviewer.crlReasonExtError.text = CRL checking failed: there was an error processing the CRL reason code extension.
+CertPathReviewer.crlReasonExtError.summary = Error processing the CRL reason code extension.
+CertPathReviewer.crlReasonExtError.details = CRL checking failed: there was an error processing the CRL reason code extension.
+
+# error processing basic constraints extension
+CertPathReviewer.crlBCExtError.title = CRL checking failed
+CertPathReviewer.crlBCExtError.text = CRL checking failed: there was an error processing the basic constraints extension.
+CertPathReviewer.crlBCExtError.summary = Error processing the basic constraints extension.
+CertPathReviewer.crlBCExtError.details = CRL checking failed: there was an error processing the basic constraints extension.
+
+# CA Cert CRL only contains user certificates
+CertPathReviewer.crlOnlyUserCert.title = CRL checking failed
+CertPathReviewer.crlOnlyUserCert.text = CRL checking failed: CRL only contains user certificates.
+CertPathReviewer.crlOnlyUserCert.summary = CRL checking failed: CRL only contains user certificates.
+CertPathReviewer.crlOnlyUserCert.details = CRL checking failed: CRL for CA certificate only contains user certificates.
+
+# End CRL only contains CA certificates
+CertPathReviewer.crlOnlyCaCert.title = CRL checking failed
+CertPathReviewer.crlOnlyCaCert.text = CRL checking failed: CRL only contains CA certificates.
+CertPathReviewer.crlOnlyCaCert.summary = CRL checking failed: CRL only contains CA certificates.
+CertPathReviewer.crlOnlyCaCert.details = CRL checking failed: CRL for end certificate only contains CA certificates.
+
+# onlyContainsAttributeCerts boolean is asserted
+CertPathReviewer.crlOnlyAttrCert.title = CRL checking failed
+CertPathReviewer.crlOnlyAttrCert.text = CRL checking failed: CRL only contains attribute certificates.
+CertPathReviewer.crlOnlyAttrCert.summary = CRL checking failed: CRL only contains attribute certificates.
+CertPathReviewer.crlOnlyAttrCert.details = CRL checking failed: CRL only contains attribute certificates.
+
+
+## QcStatement notifications
+
+# unkown statement
+# {0} statement OID
+# {1} statement as ANS1Sequence
+CertPathReviewer.QcUnknownStatement.title = Unknown statement in QcStatement extension 
+CertPathReviewer.QcUnknownStatement.text = Unknown statement in QcStatement extension: OID = {0}
+CertPathReviewer.QcUnknownStatement.summary = Unknown statement in QcStatement extension: OID = {0}
+CertPathReviewer.QcUnknownStatement.details = Unknown statement in QcStatement extension: OID = {0}, statement = {1}
+
+# QcLimitValue Alpha currency code
+# {0} currency code
+# {1} limit value
+# {2} monetary value as MonetaryValue
+CertPathReviewer.QcLimitValueAlpha.title = Transaction Value Limit
+CertPathReviewer.QcLimitValueAlpha.text = This certificate has a limit for the transaction value: {1,number,currency} {0}.
+CertPathReviewer.QcLimitValueAlpha.summary = Transaction value limit: {1,number,currency} {0}.
+CertPathReviewer.QcLimitValueAlpha.details = This certificate has a limitation on the value of transaction for which this certificate can be used to the specified amount, according to the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures, as implemented in the law of the country specified in the issuer field of this certificate. The limit for this certificate is {1,number,currency} {0}.
+
+# QcLimitValue Numeric currency code
+# {0} currency code
+# {1} limit value
+# {2} monetary value as MonetaryValue
+CertPathReviewer.QcLimitValueNum.title = Transaction Value Limit
+CertPathReviewer.QcLimitValueNum.text = This certificate has a limit for the transaction value: {1,number,currency} of currency {0} (See RFC 4217 for currency codes).
+CertPathReviewer.QcLimitValueNum.summary = Transaction value limit: {1,number,currency} of currency {0} (See RFC 4217 for currency codes).
+CertPathReviewer.QcLimitValueNum.details = This certificate has a limitation on the value of transaction for which this certificate can be used to the specified amount, according to the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures, as implemented in the law of the country specified in the issuer field of this certificate. The limit for this certificate is {1,number,currency} of currency {0} (See RFC 4217 for currency codes).
+
+# QcSSCD
+CertPathReviewer.QcSSCD.title = QcSSCD Statement
+CertPathReviewer.QcSSCD.text = The issuer claims that for the certificate where this statement appears that the private key associated with the public key in the certificate is protected according to Annex III of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures.
+CertPathReviewer.QcSSCD.summary = The issuer claims that for the certificate where this statement appears that the private key associated with the public key in the certificate is protected according to Annex III of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures.
+CertPathReviewer.QcSSCD.details = The issuer claims that for the certificate where this statement appears that the private key associated with the public key in the certificate is protected according to Annex III of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures.
+
+# QcEuCompliance
+CertPathReviewer.QcEuCompliance.title = Qualified Certificate
+CertPathReviewer.QcEuCompliance.text = This certificate is issued as a Qualified Certificate according Annex I and II of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures, as implemented in the law of the country specified in the issuer field of this certificate.
+CertPathReviewer.QcEuCompliance.summary = This certificate is issued as a Qualified Certificate according Annex I and II of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures, as implemented in the law of the country specified in the issuer field of this certificate.
+CertPathReviewer.QcEuCompliance.details = This certificate is issued as a Qualified Certificate according Annex I and II of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures, as implemented in the law of the country specified in the issuer field of this certificate. 
+
+## QcStatement errors
+
+# error processing the QcStatement extension
+CertPathReviewer.QcStatementExtError.title = Error processing the qc statements extension
+CertPathReviewer.QcStatementExtError.text = Error processing the qc statements extension.
+CertPathReviewer.QcStatementExtError.summary = Error processing the qc statements extension.
+CertPathReviewer.QcStatementExtError.details = Error processing the qc statements extension.
+
diff --git a/libcore/security/src/main/java/org/bouncycastle/x509/CertPathReviewerMessages_de.properties b/libcore/security/src/main/java/org/bouncycastle/x509/CertPathReviewerMessages_de.properties
new file mode 100644
index 0000000..52b5e5b
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/x509/CertPathReviewerMessages_de.properties
@@ -0,0 +1,563 @@
+
+## constructor exceptions 
+
+# cert path is empty
+CertPathReviewer.emptyCertPath.title = CertPath is empty
+CertPathReviewer.emptyCertPath.text = PKIXCertPathReviewer: the CertPath is empty.
+CertPathReviewer.emptyCertPath.summary = PKIXCertPathReviewer: the CertPath is empty.
+CertPathReviewer.emptyCertPath.details = PKIXCertPathReviewer: the CertPath is empty.
+
+## name constraints processing errors
+
+# cert DN is not in the permitted tree
+# {0} DN as String 
+CertPathReviewer.notPermittedDN.title = Name constraint error: certificate DN is not permitted
+CertPathReviewer.notPermittedDN.text = Name constraint error: the certificate DN {0} is not permitted.
+CertPathReviewer.notPermittedDN.summary = Name constraint error: certificate DN is not permitted.
+CertPathReviewer.notPermittedDN.details = Name constraint checking error. The certificate DN {0} is not in the permitted set of DNs.
+
+# cert DN is in the excluded tree
+# {0} DN as String
+CertPathReviewer.excludedDN.title = Name constraint error: certificate DN is excluded
+CertPathReviewer.excludedDN.text = Name constraint error: The certificate DN {0} is excluded.
+CertPathReviewer.excludedDN.summary = Name constraint error: certificate DN is excluded.
+CertPathReviewer.excludedDN.details = Name constraint checking error. The certificate DN {0} is inside of the excluded set of DNs.
+
+# cert email is not in the permitted tree
+# {0} email address as String
+CertPathReviewer.notPermittedEmail.title = Name constraint error: not permitted email address
+CertPathReviewer.notPermittedEmail.text = Name constraint error: certificate contains the not permitted email address {0}.
+CertPathReviewer.notPermittedEmail.summary = Name constraint error: not permitted email address.
+CertPathReviewer.notPermittedEmail.details = Name constraint checking error. The certificate contains the email address {0} which is not in the permitted set of email addresses.
+
+# cert email is in the excluded tree
+# {0} email as String
+CertPathReviewer.excludedEmail.title = Name constraint error: excluded email address
+CertPathReviewer.excludedEmail.text = Name constraint error: certificate contains the excluded email address {0}. 
+CertPathReviewer.excludedEmail.summary = Name constraint error: excluded email address.
+CertPathReviewer.excludedEmail.details = Name constraint checking error. The certificate contains the email address {0} which is in the excluded set of email addresses.
+
+# cert IP is not in the permitted tree
+# {0} ip address as String
+CertPathReviewer.notPermittedIP.title = Name constraint error: not permitted IP address
+CertPathReviewer.notPermittedIP.text = Name constraint error: certificate contains the not permitted IP address {0}.
+CertPathReviewer.notPermittedIP.summary = Name constraint error: not permitted IP address.
+CertPathReviewer.notPermittedIP.details = Name constraint checking error. The certificate contains the IP address {0} which is not in the permitted set of IP addresses.
+
+# cert ip is in the excluded tree
+# {0} ip address as String
+CertPathReviewer.excludedIP.title = Name constraint error: excluded IP address
+CertPathReviewer.excludedIP.text = Name constraint error: certificate contains the excluded IP address {0}.
+CertPathReviewer.excludedIP.summary = Name constraint error: excluded IP address.
+CertPathReviewer.excludedIP.details = Name constraint checking error. The certificate contains the IP address {0} which is in the excluded set of IP addresses.
+
+# error processing the name constraints extension
+CertPathReviewer.ncExtError.title = Name constraint checking failed
+CertPathReviewer.ncExtError.text = Name constraint checking failed: there was an error processing the name constraints extension of the certificate.
+CertPathReviewer.ncExtError.summary = Error processing the name constraints extension.
+CertPathReviewer.ncExtError.details = Name constraint checking failed: there was an error processing the name constraints extension of the certificate.
+
+# error processing the subject alternative name extension
+CertPathReviewer.subjAltNameExtError.title = Name constraint checking failed
+CertPathReviewer.subjAltNameExtError.text = Name constraint checking failed: there was an error processing the subject alernative name extension of the certificate.
+CertPathReviewer.subjAltNameExtError.summary = Error processing the subject alternative name extension.
+CertPathReviewer.subjAltNameExtError.details = Name constraint checking failed: there was an error processing the subject alternative name extension of the certificate.
+
+# exception extracting subject name when checking subtrees
+# {0} subject Principal
+CertPathReviewer.ncSubjectNameError.title = Name constraint checking failed
+CertPathReviewer.ncSubjectNameError.text = Name constraint checking failed: there was an exception extracting the DN from the certificate.
+CertPathReviewer.ncSubjectNameError.summary = Name constraint checking failed: exception extracting the DN.
+CertPathReviewer.ncSubjectNameError.details = Name constraint checking failed: there was an exception extracting the DN from the certificate.
+
+
+## path length errors
+
+# max path length extended
+CertPathReviewer.pathLenghtExtended.title = Maximum path length extended 
+CertPathReviewer.pathLenghtExtended.text = Certificate path invalid: Maximum path length extended.
+CertPathReviewer.pathLenghtExtended.summary = Certificate path invalid: Maximum path length extended.
+CertPathReviewer.pathLenghtExtended.details = Certificate path invalid: Maximum path length extended.
+
+# error reading length constraint from basic constraint extension
+CertPathReviewer.processLengthConstError.title = Path length checking failed
+CertPathReviewer.processLengthConstError.text = Path length checking failed: there was an error processing the basic constraint extension of the certificate. 
+CertPathReviewer.processLengthConstError.summary = Error processing the subject alternative name extension.
+CertPathReviewer.processLengthConstError.details = Path length checking failed: there was an error processing the basic constraint extension of the certificate.
+
+
+## path length notifications
+
+# total path length as defined in rfc 3280
+# {0} the path length as Integer
+CertPathReviewer.totalPathLength.title = Total path length
+CertPathReviewer.totalPathLength.text = The total path length without self-signed certificates is {0}.
+CertPathReviewer.totalPathLength.summary = The total path length without self-signed certificates is {0}.
+CertPathReviewer.totalPathLength.details = The total path length without self-signed certificates, as defined in RFC 3280, is {0}.
+
+
+## critical extensions errors
+
+# one unknown critical extension
+# {0} extension as String
+CertPathReviewer.unknownCriticalExt.title = Unknown critical extension
+CertPathReviewer.unknownCriticalExt.text = The certificate contains the unknown critical extension {0}.
+CertPathReviewer.unknownCriticalExt.summary = Unknown critical extension: {0}.
+CertPathReviewer.unknownCriticalExt.details = The certificate contains the unknown critical extension with the OID {0}.
+
+# more unknown critical extensions
+# {0} extensions as Set of Strings
+CertPathReviewer.unknownCriticalExts.title = Unknown critical extensions
+CertPathReviewer.unknownCriticalExts.text = The certificate contains two or more unknown critical extensions: {0}.
+CertPathReviewer.unknownCriticalExts.summary = Unknown critical extensions: {0}.
+CertPathReviewer.unknownCriticalExts.details = The certificate contains two or more unknown critical extensions with the OIDs: {0}.
+
+# error processing critical extension
+# {0} the message of the underlying exception
+# {1} the underlying exception
+CertPathReviewer.criticalExtensionError.title = Error processing a critical extension
+CertPathReviewer.criticalExtensionError.text = Error processing a critical extension. Cause: {0}.
+CertPathReviewer.criticalExtensionError.summary = Error processing a critical extension. Cause: {0}.
+CertPathReviewer.criticalExtensionError.details = Error processing a critical extension. Cause: {0}.
+
+# error initializing the certpath checkers
+# {0} the message of the underlying exception
+# {1} the underlying exception
+CertPathReviewer.certPathCheckerError.title = Checking critical extensions failed
+CertPathReviewer.certPathCheckerError.text = Checking critical extensions failed: there was an error initializing a CertPathChecker.
+CertPathReviewer.certPathCheckerError.summary = Checking critical extensions failed: error initializing a CertPathChecker
+CertPathReviewer.certPathCheckerError.details = Checking critical extensions failed: there was an error initializing a CertPathChecker. Cause: {0}
+
+
+## check signature errors
+
+# trustanchor found, but certificate validation failed
+CertPathReviewer.trustButInvalidCert.title = TrustAnchor found, but certificate invalid
+CertPathReviewer.trustButInvalidCert.text = A TrustAnchor was found but the certificate validation failed.
+CertPathReviewer.trustButInvalidCert.summary = TrustAnchor found but certificate validation failed.
+CertPathReviewer.trustButInvalidCert.details = A TrustAnchor was found but the certificate validation failed.
+
+# trustanchor - cannot extract issuer
+CertPathReviewer.trustAnchorIssuerError.title = Finding TrustAnchor failed 
+CertPathReviewer.trustAnchorIssuerError.text = Finding TrustAnchor failed: cannot extract issuer from certificate.
+CertPathReviewer.trustAnchorIssuerError.summary = Finding TrustAnchor failed: cannot extract issuer from certificate.
+CertPathReviewer.trustAnchorIssuerError.details = Finding TrustAnchor failed: cannot extract issuer from certificate.
+
+# no trustanchor was found for the certificate path
+# {0} issuer of the root certificate of the path
+# {1} number of trusted root certificates (trustanchors) provided
+CertPathReviewer.noTrustAnchorFound.title = No trusted root certificate found
+CertPathReviewer.noTrustAnchorFound.text = The root certificate of the certificate path was issued by a CA that is not in the the trusted-root-certificate-store used for the path validation. The name of the CA is "{0}".
+CertPathReviewer.noTrustAnchorFound.summary = The root certificate of the certificate path was issued by a CA that is not in the the trusted-root-certificate-store used for the path validation.
+CertPathReviewer.noTrustAnchorFound.details = The root certificate of the certificate path was issued by a CA that is not in the the trusted-root-certificate-store used for the path validation. The name of the CA is "{0}". The trusted-root-certificate store contains {1} CA(s).
+
+# conflicting trust anchors
+# {0} number of trustanchors found (Integer)
+# {1} the ca name
+CertPathReviewer.conflictingTrustAnchors.title = Corrupt trust root store
+CertPathReviewer.conflictingTrustAnchors.text = Warning: corrupt trust root store: There are {0} trusted public keys for the CA "{1}" - please ensure with CA which is the correct key.
+CertPathReviewer.conflictingTrustAnchors.summary = Warning: corrupt trust root store: There are {0} trusted public keys for the CA "{1}" - please ensure with CA which is the correct key.
+CertPathReviewer.conflictingTrustAnchors.details = Warning: corrupt trust root store: There are {0} trusted public keys for the CA "{1}" - please ensure with CA which is the correct key.
+
+# trustanchor DN is invalid
+# {0} DN of the Trustanchor
+CertPathReviewer.trustDNInvalid.title = DN of TrustAnchor is improperly specified
+CertPathReviewer.trustDNInvalid.text = The DN of the TrustAnchor is improperly specified: {0}.
+CertPathReviewer.trustDNInvalid.summary = The DN of the TrustAnchor is improperly specified.
+CertPathReviewer.trustDNInvalid.details = The DN of the TrustAnchor is improperly specified: {0}. It's not a valid X.500 name. See RFC 1779 or RFC 2253. 
+
+# trustanchor public key algorithm error
+CertPathReviewer.trustPubKeyError.title = Error processing public key of the trust anchor
+CertPathReviewer.trustPubKeyError.text = Error processing public key of the trust anchor.
+CertPathReviewer.trustPubKeyError.summary = Error processing public key of the trust anchor.
+CertPathReviewer.trustPubKeyError.details = Error processing public key of the trust anchor. Could not extract the AlorithmIdentifier for the key.
+
+# can not verifiy signature: issuer public key unknown
+CertPathReviewer.NoIssuerPublicKey.title = Can not verify the certificate signature 
+CertPathReviewer.NoIssuerPublicKey.text = Can not verify the certificate signature: Issuer public key is unknown.
+CertPathReviewer.NoIssuerPublicKey.summary = Can not verify the certificate signature: Issuer public key is unknown.
+CertPathReviewer.NoIssuerPublicKey.details = Can not verify the certificate signature: Issuer public key is unknown.
+
+# signature can not be verified
+# {0} message of the underlying exception (english)
+# {1} the underlying exception
+CertPathReviewer.signatureNotVerified.title = Certificate signature invalid
+CertPathReviewer.signatureNotVerified.text = The certificate signature is invalid.
+CertPathReviewer.signatureNotVerified.summary = The certificate signature is invalid.
+CertPathReviewer.signatureNotVerified.details = The certificate signature is invalid. Cause: {0}
+
+# certificate expired
+# {0} the date the certificate expired 
+CertPathReviewer.certificateExpired.title = Certificate is expired
+CertPathReviewer.certificateExpired.text = Could not validate the certificate. Certificate expired on {0,date} {0,time,full}.
+CertPathReviewer.certificateExpired.summary = Certificate expired on {0,date} {0,time,full}.
+CertPathReviewer.certificateExpired.details = Could not validate the certificate. Certificate expired on {0,date} {0,time,full}. 
+
+# certificate not yet valid
+# {0} the date from which on the certificate is valid
+CertPathReviewer.certificateNotYetValid.title = Certificate is not yet valid
+CertPathReviewer.certificateNotYetValid.text = Could not validate the certificate. Certificate is not valid untill {0,date} {0,time,full}.
+CertPathReviewer.certificateNotYetValid.summary = Certificate is not valid untill {0,date} {0,time,full}.
+CertPathReviewer.certificateNotYetValid.details = Could not validate the certificate. Certificate is not valid untill {0,date} {0,time,full}. 
+
+# certificate invalid issuer DN
+# {0} expected issuer DN as String
+# {1} found issuer DN as String
+CertPathReviewer.certWrongIssuer.title = Issuer of certificate not valid
+CertPathReviewer.certWrongIssuer.text = Issuer of certificate is not valid. Expected {0}, but found {1}. 
+CertPathReviewer.certWrongIssuer.summary = Issuer of certificate is not valid. 
+CertPathReviewer.certWrongIssuer.details = Issuer of certificate is not valid. Expected {0}, but found {1}.
+
+# intermediate certificate is no ca cert
+CertPathReviewer.noCACert.title = Certificate is no CA certificate
+CertPathReviewer.noCACert.text = Intermediate certificate is no CA certificate.
+CertPathReviewer.noCACert.summary = The certificate is no CA certificate.
+CertPathReviewer.noCACert.details = The certificate is no CA certificate but used as one.
+
+# cert laks basic constraints
+CertPathReviewer.noBasicConstraints.title = Certificate has no basic constraints
+CertPathReviewer.noBasicConstraints.text = Intermediate certificate has no basic constraints.
+CertPathReviewer.noBasicConstraints.summary = Intermediate certificate has no basic constraints.
+CertPathReviewer.noBasicConstraints.details = Intermediate certificate has no basic constraints.
+
+# error processing basic constraints
+CertPathReviewer.errorProcesingBC.title = Error processing the basic constraints extension
+CertPathReviewer.errorProcesingBC.text = There was an error while processing the basic constraints extension of this certificate.
+CertPathReviewer.errorProcesingBC.summary = Error processing the basic constraints extension. 
+CertPathReviewer.errorProcesingBC.details = There was an error while processing the basic constraints extension of this certificate.
+
+# certificate not usable for signing certs
+CertPathReviewer.noCertSign.title = Key not usable for signing certificates
+CertPathReviewer.noCertSign.text = The key usage constraint does not allow the use of this certificate key for signing certificates.
+CertPathReviewer.noCertSign.summary = The certificate key can not be used for signing certificates.
+CertPathReviewer.noCertSign.details = The key usage constraint does not allow the use of this certificate key for signing certificates.
+
+# error processing public key
+CertPathReviewer.pubKeyError.title = Error processing public key
+CertPathReviewer.pubKeyError.text = Error processing public key of the certificate.
+CertPathReviewer.pubKeyError.summary = Error processing public key of the certificate.
+CertPathReviewer.pubKeyError.details = Error processing public key of the certificate. Could not extract the AlorithmIdentifier for the key.
+
+
+## check signatures notifications
+
+# certificate path validation date
+# {0} date for which the cert path is validated
+# {1} current date
+CertPathReviewer.certPathValidDate.title = Certificate path validation date
+CertPathReviewer.certPathValidDate.text = Der Zertifikatspfad wurde am {0,date} {0,time,full} angewendet. Er wurde am {1,date} {1,time,full} validiert.
+CertPathReviewer.certPathValidDate.summary = The certificate path was validated for {0,date} {0,time,full}. It was validated at {1,date} {1,time,full}.
+CertPathReviewer.certPathValidDate.details = The certificate path was validated for {0,date} {0,time,full}. It was validated at {1,date} {1,time,full}.
+
+
+## check policy errors
+
+# error processing certificate policy extension
+CertPathReviewer.policyExtError.title = Policy checking failed
+CertPathReviewer.policyExtError.text = Policy checking failed: there was an error processing the certificate policy extension. 
+CertPathReviewer.policyExtError.summary = Error processing the certificate policy extension.
+CertPathReviewer.policyExtError.details = Policy checking failed: there was an error processing the certificate policy extension. 
+
+# error processing policy constraints extension
+CertPathReviewer.policyConstExtError.title = Policy checking failed
+CertPathReviewer.policyConstExtError.text = Policy checking failed: there was an error processing the policy constraints extension.
+CertPathReviewer.policyConstExtError.summary = Error processing the policy constraints extension.
+CertPathReviewer.policyConstExtError.details = Policy checking failed: there was an error processing the policy constraints extension.
+
+# error processing policy mapping extension
+CertPathReviewer.policyMapExtError.title = Policy checking failed
+CertPathReviewer.policyMapExtError.text = Policy checking failed: there was an error processing the policy mapping extension.
+CertPathReviewer.policyMapExtError.summary = Error processing the policy mapping extension.
+CertPathReviewer.policyMapExtError.details = Policy checking failed: there was an error processing the policy mapping extension.
+
+# error processing inhibit any policy extension
+CertPathReviewer.policyInhibitExtError.title = Policy checking failed
+CertPathReviewer.policyInhibitExtError.text = Policy checking failed: there was an error processing the policy mapping extension.
+CertPathReviewer.policyInhibitExtError.summary = Error processing the inhibit any policy extension.
+CertPathReviewer.policyInhibitExtError.details = Policy checking failed: there was an error processing the policy mapping extension.
+
+# error building qualifier set
+CertPathReviewer.policyQualifierError.title = Policy checking failed
+CertPathReviewer.policyQualifierError.text = Policy checking failed: error building the policy qualifier set.
+CertPathReviewer.policyQualifierError.summary = Policy checking failed: error building the policy qualifier set.
+CertPathReviewer.policyQualifierError.details = Policy checking failed: error building the policy qualifier set.
+
+# no valid policy tree - explicit policy required
+CertPathReviewer.noValidPolicyTree.title = Policy checking failed
+CertPathReviewer.noValidPolicyTree.text = Policy checking failed: no valid policy tree found when one expected.
+CertPathReviewer.noValidPolicyTree.summary = Policy checking failed: no valid policy tree found when one expected.
+CertPathReviewer.noValidPolicyTree.details = Policy checking failed: no valid policy tree found when one expected.
+
+# expicit policy requested, but no policy available
+CertPathReviewer.explicitPolicy.title = Policy checking failed
+CertPathReviewer.explicitPolicy.text = Policy checking failed: explicit policy requested but no policy available.
+CertPathReviewer.explicitPolicy.summary = Policy checking failed: explicit policy requested but no policy available.
+CertPathReviewer.explicitPolicy.details = Policy checking failed: explicit policy requested but no policy available.
+
+# path processing failed on policy
+CertPathReviewer.invalidPolicy.title = Path processing failed on policy
+CertPathReviewer.invalidPolicy.text = Path processing failed on policy.
+CertPathReviewer.invalidPolicy.summary = Path processing failed on policy.
+CertPathReviewer.invalidPolicy.details = Path processing failed on policy.
+
+# invalid policy mapping
+CertPathReviewer.invalidPolicyMapping.title = Invalid policy mapping 
+CertPathReviewer.invalidPolicyMapping.text = Certificate contains an invalid policy mapping.
+CertPathReviewer.invalidPolicyMapping.summary = Certificate contains an invalid policy mapping. 
+CertPathReviewer.invalidPolicyMapping.details = Certificate contains a policy mapping including the value any policy which is invalid.
+
+## check CRL notifications
+
+# found local valid CRL
+# {0} thisUpdate of the CRL
+# {1} nextUpdate of the CRL
+CertPathReviewer.localValidCRL.title = Found valid local CRL
+CertPathReviewer.localValidCRL.text = Found a valid CRL in local certstore. Issued on {0,date}, next update {1,date}.
+CertPathReviewer.localValidCRL.summary = Found a valid CRL in local certstore. Issued on {0,date}, next update {1,date}.
+CertPathReviewer.localValidCRL.details = Found a valid CRL in local certstore. Issued on {0,date}, next update {1,date}.
+
+
+# found matching CRL, but not valid
+# {0} thisUpdate of the CRL
+# {1} nextUpdate of the CRL
+CertPathReviewer.localInvalidCRL.title = Local CRL outdated
+CertPathReviewer.localInvalidCRL.text = Did not use a matching CRL in a local certstore, because it is outdated. Issued on {0,date}, next update {1,date}.
+CertPathReviewer.localInvalidCRL.summary = Did not use a matching CRL in a local certstore, because it is outdated. Issued on {0,date}, next update {1,date}.
+CertPathReviewer.localInvalidCRL.details = Did not use a matching CRL in a local certstore, because it is outdated. Issued on {0,date}, next update {1,date}.
+
+# found a valid crl at crl distribution point
+# {0} thisUpdate of the CRL
+# {1} nextUpdate of the CRL
+# {2} the url of the distribution point
+CertPathReviewer.onlineValidCRL.title = Found valid CRL at CRL distribution point
+CertPathReviewer.onlineValidCRL.text = Found a valid CRL at: {2}. Issued on {0,date}, next update on {1,date}.
+CertPathReviewer.onlineValidCRL.summary = Found a valid CRL at: {2}. Issued on {0,date}, next update on {1,date}.
+CertPathReviewer.onlineValidCRL.details = Found a valid CRL at: {2}. Issued on {0,date}, next update on {1,date}.
+
+# found an invalid CRL at crl distribution point
+# {0} thisUpdate of the CRL
+# {1} nextUpdate of the CRL
+# {2} the url of the distribution point
+CertPathReviewer.onlineInvalidCRL.title = Outdated CRL at CRL distribution point
+CertPathReviewer.onlineInvalidCRL.text = The CRL loaded from {2} was outdated. Issued on {0,date}, next update on {1,date}.
+CertPathReviewer.onlineInvalidCRL.summary = The CRL loaded from {2} was outdated. Issued on {0,date}, next update on {1,date}.
+CertPathReviewer.onlineInvalidCRL.details = The CRL loaded from {2} was outdated. Issued on {0,date}, next update on {1,date}.
+
+# Certificate not revoked
+CertPathReviewer.notRevoked.title = Certificate not revoked
+CertPathReviewer.notRevoked.text = The certificate was not revoked.
+CertPathReviewer.notRevoked.summary = The certificate was not revoked.
+CertPathReviewer.notRevoked.details = The certificate was not revoked.
+
+# CRL found: certificate was revoked, but after the validationDate
+# {0} the date the certificate was revoked
+# {1} the reason for revoking the certificate
+CertPathReviewer.revokedAfterValidation.title = Certificate was revoked after the validation date
+CertPathReviewer.revokedAfterValidation.text = The certificate was revoked after the validation date at {0,date} {0,time,full}. Reason: {1}.
+CertPathReviewer.revokedAfterValidation.summary = The certificate was revoked after the validation date at {0,date} {0,time,full}.
+CertPathReviewer.revokedAfterValidation.details = The certificate was revoked after the validation date at {0,date} {0,time,full}. Reason: {1}.
+
+# updated crl available
+# {0} date since when the update is available
+CertPathReviewer.crlUpdateAvailable.title = CRL update available
+CertPathReviewer.crlUpdateAvailable.text = An update for the CRL of this certificate is available since {0,date} {0,time,full}.
+CertPathReviewer.crlUpdateAvailable.summary = An update for the CRL of this certificate is available since {0,date} {0,time,full}.
+CertPathReviewer.crlUpdateAvailable.details = An update for the CRL of this certificate is available since {0,date} {0,time,full}.
+
+# crl distribution point url
+# {0} the crl distribution point url as String
+CertPathReviewer.crlDistPoint.title = CRL distribution point
+CertPathReviewer.crlDistPoint.text = A CRL can be obtained from: {0}.
+CertPathReviewer.crlDistPoint.summary = A CRL can be obtained from: {0}.
+CertPathReviewer.crlDistPoint.details = A CRL can be obtained from: {0}.
+
+# ocsp location
+# {0} the url on which the ocsp service can be found
+CertPathReviewer.ocspLocation.title = OCSP responder location
+CertPathReviewer.ocspLocation.text = OCSP responder location: {0}.
+CertPathReviewer.ocspLocation.summary = OCSP responder location: {0}.
+CertPathReviewer.ocspLocation.details = OCSP responder location: {0}.
+
+# unable to get crl from crl distribution point
+# {0} the url of the distribution point
+# {1} the message of the occured exception
+# {2} the occured exception
+CertPathReviewer.loadCrlDistPointError.title = Cannot load CRL from CRL distribution point
+CertPathReviewer.loadCrlDistPointError.text = Unable to load a CRL from: {0}. An Exception occured.
+CertPathReviewer.loadCrlDistPointError.summary = Unable to load a CRL from: {0}. An Exception occured.
+CertPathReviewer.loadCrlDistPointError.details = Unable to load a CRL from: {0}. An Exception occured: Cause: {1}.
+
+# no crl found in certstores
+# {0} the issuers which we searched for
+# {1} list of crl issuer names that are found in the certstores
+# {2} number of crls in the certstores
+CertPathReviewer.noCrlInCertstore.title = No matching CRL found in local certstores
+CertPathReviewer.noCrlInCertstore.text = No matching CRL was found in the provided local certstore.
+CertPathReviewer.noCrlInCertstore.summary = No matching CRL was found in the provided local certstore.
+CertPathReviewer.noCrlInCertstore.details = No matching CRL was found in the provided local certstore. \
+No CRL was found for the selector "{0}". The {2} CRL(s) in the certstores are from "{1}".
+
+
+## check CRL exceptions
+
+# cannot extract issuer from certificate
+CertPathReviewer.crlIssuerException.title = CRL checking failed
+CertPathReviewer.crlIssuerException.text = CRL checking failed: cannot extract issuer from certificate.
+CertPathReviewer.crlIssuerException.summary = CRL checking failed: cannot extract issuer from certificate.
+CertPathReviewer.crlIssuerException.details = CRL checking failed: cannot extract issuer from certificate.
+
+# cannot extract crls
+# {0} message from the underlying exception
+# {1} the underlying exception
+CertPathReviewer.crlExtractionError.title = CRL checking failed
+CertPathReviewer.crlExtractionError.text = CRL checking failed: Cannot extract CRL from CertStore.
+CertPathReviewer.crlExtractionError.summary = CRL checking failed: Cannot extract CRL from CertStore.
+CertPathReviewer.crlExtractionError.details = CRL checking failed: Cannot extract CRL from CertStore. Cause: {0}.
+
+# Issuer certificate key usage extension does not permit crl signing
+CertPathReviewer.noCrlSigningPermited.title = CRL checking failed
+CertPathReviewer.noCrlSigningPermited.text = CRL checking failed: issuer certificate does not permit CRL signing.
+CertPathReviewer.noCrlSigningPermited.summary = CRL checking failed: issuer certificate does not permit CRL signing.
+CertPathReviewer.noCrlSigningPermited.details = CRL checking failed: issuer certificate does not permit CRL signing.
+
+# can not verify crl: issuer public key unknown
+CertPathReviewer.crlNoIssuerPublicKey.title = CRL checking failed
+CertPathReviewer.crlNoIssuerPublicKey.text = CRL checking failed: Can not verify the CRL: Issuer public key is unknown.
+CertPathReviewer.crlNoIssuerPublicKey.summary = CRL checking failed: Can not verify the CRL: Issuer public key is unknown.
+CertPathReviewer.crlNoIssuerPublicKey.details = CRL checking failed: Can not verify the CRL: Issuer public key is unknown.
+
+# crl verification failed
+CertPathReviewer.crlVerifyFailed.title = CRL checking failed
+CertPathReviewer.crlVerifyFailed.text = CRL checking failed: CRL signature is invalid.
+CertPathReviewer.crlVerifyFailed.summary = CRL checking failed: CRL signature is invalid.
+CertPathReviewer.crlVerifyFailed.details = CRL checking failed: CRL signature is invalid.
+
+# no valid CRL found
+CertPathReviewer.noValidCrlFound.title = CRL checking failed
+CertPathReviewer.noValidCrlFound.text = CRL checking failed: no valid CRL found.
+CertPathReviewer.noValidCrlFound.summary = CRL checking failed: no valid CRL found.
+CertPathReviewer.noValidCrlFound.details = CRL checking failed: no valid CRL found.
+
+# No base CRL for delta CRL
+CertPathReviewer.noBaseCRL.title = CRL checking failed
+CertPathReviewer.noBaseCRL.text = CRL checking failed: no base CRL found for delta CRL.
+CertPathReviewer.noBaseCRL.summary = CRL checking failed: no base CRL found for delta CRL.
+CertPathReviewer.noBaseCRL.details = CRL checking failed: no base CRL found for delta CRL.
+
+# certificate revoked
+# {0} the date the certificate was revoked
+# {1} the reason for revoking the certificate
+CertPathReviewer.certRevoked.title = Certificate was revoked
+CertPathReviewer.certRevoked.text = The certificate is invalid, because it was revoked at {0,date} {0,time,full}. Reason: {1}.
+CertPathReviewer.certRevoked.summary = The certificate is invalid, because it was revoked at {0,date} {0,time,full}.
+CertPathReviewer.certRevoked.details = The certificate is invalid, because it was revoked at {0,date} {0,time,full}. Reason: {1}.
+
+# error processing issuing distribution point extension
+CertPathReviewer.distrPtExtError.title = CRL checking failed
+CertPathReviewer.distrPtExtError.text = CRL checking failed: there was an error processing the issuing distribution point extension. 
+CertPathReviewer.distrPtExtError.summary = Error processing the issuing distribution point extension.
+CertPathReviewer.distrPtExtError.details = CRL checking failed: there was an error processing the issuing distribution point extension.
+
+# error processing crl distribution points extension
+CertPathReviewer.crlDistPtExtError.title = CRL checking failed
+CertPathReviewer.crlDistPtExtError.text = CRL checking failed: there was an error processing the crl distribution points extension.
+CertPathReviewer.crlDistPtExtError.summary = Error processing the crl distribution points extension.
+CertPathReviewer.crlDistPtExtError.details = CRL checking failed: there was an error processing the crl distribution points extension.
+
+# error processing the authority info access extension
+CertPathReviewer.crlAuthInfoAccError.title = CRL checking failed
+CertPathReviewer.crlAuthInfoAccError.text = CRL checking failed: there was an error processing the authority info access extension.
+CertPathReviewer.crlAuthInfoAccError.summary = Error processing the authority info access extension.
+CertPathReviewer.crlAuthInfoAccError.details = CRL checking failed: there was an error processing the authority info access extension.
+
+# error processing delta crl indicator extension
+CertPathReviewer.deltaCrlExtError.title = CRL checking failed
+CertPathReviewer.deltaCrlExtError.text = CRL checking failed: there was an error processing the delta CRL indicator extension. 
+CertPathReviewer.deltaCrlExtError.summary = Error processing the delta CRL indicator extension.
+CertPathReviewer.deltaCrlExtError.details = CRL checking failed: there was an error processing the delta CRL indicator extension.
+
+# error porcessing crl number extension
+CertPathReviewer.crlNbrExtError.title = CRL checking failed
+CertPathReviewer.crlNbrExtError.text = CRL checking failed: there was an error processing the CRL number extension.
+CertPathReviewer.crlNbrExtError.summary = Error processing the CRL number extension.
+CertPathReviewer.crlNbrExtError.details = CRL checking failed: there was an error processing the CRL number extension.
+
+# error processing crl reason code extension
+CertPathReviewer.crlReasonExtError.title = CRL checking failed
+CertPathReviewer.crlReasonExtError.text = CRL checking failed: there was an error processing the CRL reason code extension.
+CertPathReviewer.crlReasonExtError.summary = Error processing the CRL reason code extension.
+CertPathReviewer.crlReasonExtError.details = CRL checking failed: there was an error processing the CRL reason code extension.
+
+# error processing basic constraints extension
+CertPathReviewer.crlBCExtError.title = CRL checking failed
+CertPathReviewer.crlBCExtError.text = CRL checking failed: there was an error processing the basic constraints extension.
+CertPathReviewer.crlBCExtError.summary = Error processing the basic constraints extension.
+CertPathReviewer.crlBCExtError.details = CRL checking failed: there was an error processing the basic constraints extension.
+
+# CA Cert CRL only contains user certificates
+CertPathReviewer.crlOnlyUserCert.title = CRL checking failed
+CertPathReviewer.crlOnlyUserCert.text = CRL checking failed: CRL only contains user certificates.
+CertPathReviewer.crlOnlyUserCert.summary = CRL checking failed: CRL only contains user certificates.
+CertPathReviewer.crlOnlyUserCert.details = CRL checking failed: CRL for CA certificate only contains user certificates.
+
+# End CRL only contains CA certificates
+CertPathReviewer.crlOnlyCaCert.title = CRL checking failed
+CertPathReviewer.crlOnlyCaCert.text = CRL checking failed: CRL only contains CA certificates.
+CertPathReviewer.crlOnlyCaCert.summary = CRL checking failed: CRL only contains CA certificates.
+CertPathReviewer.crlOnlyCaCert.details = CRL checking failed: CRL for end certificate only contains CA certificates.
+
+# onlyContainsAttributeCerts boolean is asserted
+CertPathReviewer.crlOnlyAttrCert.title = CRL checking failed
+CertPathReviewer.crlOnlyAttrCert.text = CRL checking failed: CRL only contains attribute certificates.
+CertPathReviewer.crlOnlyAttrCert.summary = CRL checking failed: CRL only contains attribute certificates.
+CertPathReviewer.crlOnlyAttrCert.details = CRL checking failed: CRL only contains attribute certificates.
+
+
+## QcStatement notifications
+
+# unkown statement
+# {0} statement OID
+# {1} statement as ANS1Sequence
+CertPathReviewer.QcUnknownStatement.title = Unknown statement in QcStatement extension 
+CertPathReviewer.QcUnknownStatement.text = Unknown statement in QcStatement extension: OID = {0}
+CertPathReviewer.QcUnknownStatement.summary = Unknown statement in QcStatement extension: OID = {0}
+CertPathReviewer.QcUnknownStatement.details = Unknown statement in QcStatement extension: OID = {0}, statement = {1}
+
+# QcLimitValue Alpha currency code
+# {0} currency code
+# {1} limit value
+# {2} monetary value as MonetaryValue
+CertPathReviewer.QcLimitValueAlpha.title = Transaction Value Limit
+CertPathReviewer.QcLimitValueAlpha.text = This certificate has a limit for the transaction value: {1,number,currency} {0}.
+CertPathReviewer.QcLimitValueAlpha.summary = Transaction value limit: {1,number,currency} {0}.
+CertPathReviewer.QcLimitValueAlpha.details = This certificate has a limitation on the value of transaction for which this certificate can be used to the specified amount, according to the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures, as implemented in the law of the country specified in the issuer field of this certificate. The limit for this certificate is {1,number,currency} {0}.
+
+# QcLimitValue Numeric currency code
+# {0} currency code
+# {1} limit value
+# {2} monetary value as MonetaryValue
+CertPathReviewer.QcLimitValueNum.title = Transaction Value Limit
+CertPathReviewer.QcLimitValueNum.text = This certificate has a limit for the transaction value: {1,number,currency} of currency {0} (See RFC 4217 for currency codes).
+CertPathReviewer.QcLimitValueNum.summary = Transaction value limit: {1,number,currency} of currency {0} (See RFC 4217 for currency codes).
+CertPathReviewer.QcLimitValueNum.details = This certificate has a limitation on the value of transaction for which this certificate can be used to the specified amount, according to the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures, as implemented in the law of the country specified in the issuer field of this certificate. The limit for this certificate is {1,number,currency} of currency {0} (See RFC 4217 for currency codes).
+
+# QcSSCD
+CertPathReviewer.QcSSCD.title = QcSSCD Statement
+CertPathReviewer.QcSSCD.text = The issuer claims that for the certificate where this statement appears that the private key associated with the public key in the certificate is protected according to Annex III of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures.
+CertPathReviewer.QcSSCD.summary = The issuer claims that for the certificate where this statement appears that the private key associated with the public key in the certificate is protected according to Annex III of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures.
+CertPathReviewer.QcSSCD.details = The issuer claims that for the certificate where this statement appears that the private key associated with the public key in the certificate is protected according to Annex III of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures.
+
+# QcEuCompliance
+CertPathReviewer.QcEuCompliance.title = Qualified Certificate
+CertPathReviewer.QcEuCompliance.text = This certificate is issued as a Qualified Certificate according Annex I and II of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures, as implemented in the law of the country specified in the issuer field of this certificate.
+CertPathReviewer.QcEuCompliance.summary = This certificate is issued as a Qualified Certificate according Annex I and II of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures, as implemented in the law of the country specified in the issuer field of this certificate.
+CertPathReviewer.QcEuCompliance.details = This certificate is issued as a Qualified Certificate according Annex I and II of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures, as implemented in the law of the country specified in the issuer field of this certificate. 
+
+## QcStatement errors
+
+# error processing the QcStatement extension
+CertPathReviewer.QcStatementExtError.title = Error processing the qc statements extension
+CertPathReviewer.QcStatementExtError.text = Error processing the qc statements extension.
+CertPathReviewer.QcStatementExtError.summary = Error processing the qc statements extension.
+CertPathReviewer.QcStatementExtError.details = Error processing the qc statements extension.
+
diff --git a/libcore/security/src/main/java/org/bouncycastle/x509/PKIXCertPathReviewer.java b/libcore/security/src/main/java/org/bouncycastle/x509/PKIXCertPathReviewer.java
new file mode 100644
index 0000000..50037db
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/x509/PKIXCertPathReviewer.java
@@ -0,0 +1,2437 @@
+package org.bouncycastle.x509;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.URL;
+import java.security.GeneralSecurityException;
+import java.security.PublicKey;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.PKIXParameters;
+import java.security.cert.PolicyNode;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509CRLSelector;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DEREnumerated;
+import org.bouncycastle.asn1.DERIA5String;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.x509.AccessDescription;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.AuthorityInformationAccess;
+import org.bouncycastle.asn1.x509.BasicConstraints;
+import org.bouncycastle.asn1.x509.CRLDistPoint;
+import org.bouncycastle.asn1.x509.DistributionPoint;
+import org.bouncycastle.asn1.x509.DistributionPointName;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.GeneralNames;
+import org.bouncycastle.asn1.x509.GeneralSubtree;
+import org.bouncycastle.asn1.x509.IssuingDistributionPoint;
+import org.bouncycastle.asn1.x509.NameConstraints;
+import org.bouncycastle.asn1.x509.PolicyInformation;
+import org.bouncycastle.asn1.x509.X509Extensions;
+import org.bouncycastle.asn1.x509.X509Name;
+import org.bouncycastle.asn1.x509.qualified.Iso4217CurrencyCode;
+import org.bouncycastle.asn1.x509.qualified.MonetaryValue;
+import org.bouncycastle.asn1.x509.qualified.QCStatement;
+import org.bouncycastle.i18n.ErrorBundle;
+import org.bouncycastle.i18n.filter.UntrustedInput;
+import org.bouncycastle.jce.provider.CertPathValidatorUtilities;
+import org.bouncycastle.jce.provider.PKIXPolicyNode;
+import org.bouncycastle.jce.provider.AnnotatedException;
+
+/**
+ * PKIXCertPathReviewer<br>
+ * Validation of X.509 Certificate Paths. Tries to find as much errors in the Path as possible.
+ */
+public class PKIXCertPathReviewer extends CertPathValidatorUtilities
+{
+    
+    private static final String QC_STATEMENT = X509Extensions.QCStatements.getId();
+    private static final String CRL_DIST_POINTS = X509Extensions.CRLDistributionPoints.getId();
+    private static final String AUTH_INFO_ACCESS = X509Extensions.AuthorityInfoAccess.getId();
+    
+    private static final String RESOURCE_NAME = "org.bouncycastle.x509.CertPathReviewerMessages";
+    
+    // input parameters
+    
+    protected CertPath certPath;
+
+    protected PKIXParameters pkixParams;
+
+    protected Date validDate;
+
+    // state variables
+    
+    protected List certs;
+
+    protected int n;
+    
+    // output variables
+    
+    protected List[] notifications;
+    protected List[] errors;
+    protected TrustAnchor trustAnchor;
+    protected PublicKey subjectPublicKey;
+    protected PolicyNode policyTree;
+    
+    
+    /**
+     * Creates a PKIXCertPathReviewer for the given {@link CertPath} and {@link PKIXParameters} params
+     * @param certPath the {@link CertPath} to validate
+     * @param params the {@link PKIXParameters} to use
+     * @throws CertPathReviewerException if the certPath is empty
+     */
+    public PKIXCertPathReviewer(CertPath certPath, PKIXParameters params)
+            throws CertPathReviewerException
+    {
+        // check input parameters
+        if (certPath == null)
+        {
+            throw new NullPointerException("certPath was null");
+        }
+        this.certPath = certPath;
+
+        certs = certPath.getCertificates();
+        n = certs.size();
+        if (certs.isEmpty())
+        {
+            throw new CertPathReviewerException(
+                    new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.emptyCertPath"));
+        }
+
+        pkixParams = (PKIXParameters) params.clone();
+
+        // 6.1.1 - Inputs
+
+        // a) done
+
+        // b)
+
+        validDate = getValidDate(pkixParams);
+
+        // c) part of pkixParams
+
+        // d) done at the beginning of checkSignatures
+
+        // e) f) g) part of pkixParams
+        
+        // initialize output parameters
+        
+        notifications = null;
+        errors = null;
+        trustAnchor = null;
+        subjectPublicKey = null;
+        policyTree = null;
+
+    }
+    
+    /**
+     * 
+     * @return the CertPath that was validated
+     */
+    public CertPath getCertPath()
+    {
+        return certPath;
+    }
+    
+    /**
+     * 
+     * @return the size of the CertPath
+     */
+    public int getCertPathSize()
+    {
+        return n;
+    }
+
+    /**
+     * Returns an Array of Lists which contains a List of global error messages 
+     * and a List of error messages for each certificate in the path.
+     * The global error List is at index 0. The error lists for each certificate at index 1 to n. 
+     * The error messages are of type.
+     * @return the Array of Lists which contain the error messages
+     */
+    public List[] getErrors()
+    {
+        doChecks();
+        return errors;
+    }
+    
+    /**
+     * Returns an List of error messages for the certificate at the given index in the CertPath.
+     * If index == -1 then the list of global errors is returned with errors not specific to a certificate. 
+     * @param index the index of the certificate in the CertPath
+     * @return List of error messages for the certificate
+     */
+    public List getErrors(int index)
+    {
+        doChecks();
+        return errors[index + 1];
+    }
+
+    /**
+     * Returns an Array of Lists which contains a List of global notification messages 
+     * and a List of botification messages for each certificate in the path.
+     * The global notificatio List is at index 0. The notification lists for each certificate at index 1 to n. 
+     * The error messages are of type.
+     * @return the Array of Lists which contain the notification messages
+     */
+    public List[] getNotifications()
+    {
+        doChecks();
+        return notifications;
+    }
+    
+    /**
+     * Returns an List of notification messages for the certificate at the given index in the CertPath.
+     * If index == -1 then the list of global notifications is returned with notifications not specific to a certificate. 
+     * @param index the index of the certificate in the CertPath
+     * @return List of notification messages for the certificate
+     */
+    public List getNotifications(int index)
+    {
+        doChecks();
+        return notifications[index + 1];
+    }
+
+    /**
+     * 
+     * @return the valid policy tree, <b>null</b> if no valid policy exists.
+     */
+    public PolicyNode getPolicyTree()
+    {
+        doChecks();
+        return policyTree;
+    }
+
+    /**
+     * 
+     * @return the PublicKey if the last certificate in the CertPath
+     */
+    public PublicKey getSubjectPublicKey()
+    {
+        doChecks();
+        return subjectPublicKey;
+    }
+
+    /**
+     * 
+     * @return the TrustAnchor for the CertPath, <b>null</b> if no valid TrustAnchor was found.
+     */
+    public TrustAnchor getTrustAnchor()
+    {
+        doChecks();
+        return trustAnchor;
+    }
+    
+    /**
+     * 
+     * @return if the CertPath is valid
+     */
+    public boolean isValidCertPath()
+    {
+        doChecks();
+        boolean valid = true;
+        for (int i = 0; i < errors.length; i++)
+        {
+            if (!errors[i].isEmpty())
+            {
+                valid = false;
+                break;
+            }
+        }
+        return valid;
+    }
+    
+    protected void addNotification(ErrorBundle msg)
+    {
+        notifications[0].add(msg);
+    }
+    
+    protected void addNotification(ErrorBundle msg, int index)
+    {
+        if (index < -1 || index >= n)
+        {
+            throw new IndexOutOfBoundsException();
+        }
+        notifications[index + 1].add(msg);
+    }
+
+    protected void addError(ErrorBundle msg) 
+    {
+        errors[0].add(msg);
+    }
+    
+    protected void addError(ErrorBundle msg, int index)
+    {
+        if (index < -1 || index >= n)
+        {
+            throw new IndexOutOfBoundsException();
+        }
+        errors[index + 1].add(msg);
+    }
+    
+    protected void doChecks()
+    {
+        if (notifications == null)
+        {
+            // initialize lists
+            notifications = new List[n+1];
+            errors = new List[n+1];
+            
+            for (int i = 0; i < notifications.length; i++)
+            {
+                notifications[i] = new ArrayList();
+                errors[i] = new ArrayList();
+            }
+            
+            // check Signatures
+            checkSignatures();
+            
+            // check Name Constraints
+            checkNameConstraints();
+            
+            // check Path Length
+            checkPathLength();
+            
+            // check Policy
+            checkPolicy();
+            
+            // check other critical extensions
+            checkCriticalExtensions();
+            
+        }
+    }
+
+    private void checkNameConstraints()
+    {
+        X509Certificate cert = null;
+        
+        //
+        // Setup
+        //
+        
+        // (b)
+        Set     permittedSubtreesDN = new HashSet();
+        Set     permittedSubtreesEmail = new HashSet();
+        Set     permittedSubtreesIP = new HashSet();
+    
+        // (c)
+        Set     excludedSubtreesDN = new HashSet();
+        Set     excludedSubtreesEmail = new HashSet();
+        Set     excludedSubtreesIP = new HashSet();
+
+        //
+        // process each certificate except the last in the path
+        //
+        int index;
+        int i;
+        
+        try 
+        {
+            for (index = certs.size()-1; index>0; index--) 
+            {
+                i = n - index;
+                
+                //
+                // certificate processing
+                //    
+                
+                cert = (X509Certificate) certs.get(index);
+                
+                // b),c)
+                
+                if (!isSelfIssued(cert))
+                {
+                    X500Principal principal = getSubjectPrincipal(cert);
+                    ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(principal.getEncoded()));
+                    ASN1Sequence    dns;
+    
+                    try
+                    {
+                        dns = (ASN1Sequence)aIn.readObject();
+                    }
+                    catch (IOException e)
+                    {
+                        ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.ncSubjectNameError", 
+                                new Object[] {new UntrustedInput(principal)});
+                        throw new CertPathReviewerException(msg,e,certPath,index);
+                    }
+    
+                    try
+                    {
+                        checkPermittedDN(permittedSubtreesDN, dns);
+                    }
+                    catch (CertPathValidatorException cpve)
+                    {
+                        ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.notPermittedDN", 
+                                new Object[] {new UntrustedInput(principal.getName())});
+                        throw new CertPathReviewerException(msg,cpve,certPath,index);
+                    }
+                    
+                    try
+                    {
+                        checkExcludedDN(excludedSubtreesDN, dns);
+                    }
+                    catch (CertPathValidatorException cpve)
+                    {
+                        ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.excludedDN",
+                                new Object[] {new UntrustedInput(principal.getName())});
+                        throw new CertPathReviewerException(msg,cpve,certPath,index);
+                    }
+            
+                    ASN1Sequence altName;
+                    try 
+                    {
+                        altName = (ASN1Sequence)getExtensionValue(cert, SUBJECT_ALTERNATIVE_NAME);
+                    }
+                    catch (AnnotatedException ae)
+                    {
+                        ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.subjAltNameExtError");
+                        throw new CertPathReviewerException(msg,ae,certPath,index);
+                    }
+                    
+                    if (altName != null)
+                    {
+                        for (int j = 0; j < altName.size(); j++)
+                        {
+                            ASN1TaggedObject o = (ASN1TaggedObject)altName.getObjectAt(j);
+    
+                            switch(o.getTagNo())
+                            {
+                            case 1:
+                                String email = DERIA5String.getInstance(o, true).getString();
+    
+                                try
+                                {
+                                    checkPermittedEmail(permittedSubtreesEmail, email);
+                                }
+                                catch (CertPathValidatorException cpve)
+                                {
+                                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.notPermittedEmail", 
+                                            new Object[] {new UntrustedInput(email)});
+                                    throw new CertPathReviewerException(msg,cpve,certPath,index);
+                                }
+                                
+                                try
+                                {
+                                    checkExcludedEmail(excludedSubtreesEmail, email);
+                                }
+                                catch (CertPathValidatorException cpve)
+                                {
+                                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.excludedEmail", 
+                                            new Object[] {new UntrustedInput(email)});
+                                    throw new CertPathReviewerException(msg,cpve,certPath,index);
+                                }
+
+                                break;
+                            case 4:
+                                ASN1Sequence altDN = ASN1Sequence.getInstance(o, true);
+    
+                                try
+                                {
+                                    checkPermittedDN(permittedSubtreesDN, altDN);
+                                }
+                                catch (CertPathValidatorException cpve)
+                                {
+                                    X509Name altDNName = new X509Name(altDN);
+                                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.notPermittedDN", 
+                                            new Object[] {new UntrustedInput(altDNName)});
+                                    throw new CertPathReviewerException(msg,cpve,certPath,index);
+                                }
+                                
+                                try
+                                {
+                                    checkExcludedDN(excludedSubtreesDN, altDN);
+                                }
+                                catch (CertPathValidatorException cpve)
+                                {
+                                    X509Name altDNName = new X509Name(altDN);
+                                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.excludedDN", 
+                                            new Object[] {new UntrustedInput(altDNName)});
+                                    throw new CertPathReviewerException(msg,cpve,certPath,index);
+                                }
+                                
+                                break;
+                            case 7:
+                                byte[] ip = ASN1OctetString.getInstance(o, true).getOctets();
+    
+                                try
+                                {
+                                    checkPermittedIP(permittedSubtreesIP, ip);
+                                }
+                                catch (CertPathValidatorException cpve)
+                                {
+                                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.notPermittedIP", 
+                                            new Object[] {IPtoString(ip)});
+                                    throw new CertPathReviewerException(msg,cpve,certPath,index);
+                                }
+                                
+                                try
+                                {
+                                    checkExcludedIP(excludedSubtreesIP, ip);
+                                }
+                                catch (CertPathValidatorException cpve)
+                                {
+                                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.excludedIP", 
+                                            new Object[] {IPtoString(ip)});
+                                    throw new CertPathReviewerException(msg,cpve,certPath,index);
+                                }
+                            }
+                        }
+                    }
+                }
+                
+                //
+                // prepare for next certificate
+                //
+                
+                //
+                // (g) handle the name constraints extension
+                //
+                ASN1Sequence ncSeq;
+                try 
+                {
+                    ncSeq = (ASN1Sequence)getExtensionValue(cert, NAME_CONSTRAINTS);
+                }
+                catch (AnnotatedException ae)
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.ncExtError");
+                    throw new CertPathReviewerException(msg,ae,certPath,index);
+                }
+                
+                if (ncSeq != null)
+                {
+                    NameConstraints nc = new NameConstraints(ncSeq);
+
+                    //
+                    // (g) (1) permitted subtrees
+                    //
+                    ASN1Sequence permitted = nc.getPermittedSubtrees();
+                    if (permitted != null)
+                    {
+                        Enumeration e = permitted.getObjects();
+                        while (e.hasMoreElements())
+                        {
+                            GeneralSubtree  subtree = GeneralSubtree.getInstance(e.nextElement());
+                            GeneralName     base = subtree.getBase();
+
+                            switch(base.getTagNo())
+                            {
+                                case 1:
+                                    permittedSubtreesEmail = intersectEmail(permittedSubtreesEmail, DERIA5String.getInstance(base.getName()).getString());
+                                    break;
+                                case 4:
+                                    permittedSubtreesDN = intersectDN(permittedSubtreesDN, (ASN1Sequence)base.getName());
+                                    break;
+                                case 7:
+                                    permittedSubtreesIP = intersectIP(permittedSubtreesIP, ASN1OctetString.getInstance(base.getName()).getOctets());
+                                    break;
+                            }
+                        }
+                    }
+                
+                    //
+                    // (g) (2) excluded subtrees
+                    //
+                    ASN1Sequence excluded = nc.getExcludedSubtrees();
+                    if (excluded != null)
+                    {
+                        Enumeration e = excluded.getObjects();
+                        while (e.hasMoreElements())
+                        {
+                            GeneralSubtree  subtree = GeneralSubtree.getInstance(e.nextElement());
+                            GeneralName     base = subtree.getBase();
+
+                            switch(base.getTagNo())
+                            {
+                            case 1:
+                                excludedSubtreesEmail = unionEmail(excludedSubtreesEmail, DERIA5String.getInstance(base.getName()).getString());
+                                break;
+                            case 4:
+                                excludedSubtreesDN = unionDN(excludedSubtreesDN, (ASN1Sequence)base.getName());
+                                break;
+                            case 7:
+                                excludedSubtreesIP = unionIP(excludedSubtreesIP, ASN1OctetString.getInstance(base.getName()).getOctets());
+                                break;
+                            }
+                        }
+                    }
+                }
+                
+            } // for
+        }
+        catch (CertPathReviewerException cpre)
+        {
+            addError(cpre.getErrorMessage(),cpre.getIndex());
+        }
+        
+    }
+
+    /*
+     * checks: - path length constraints and reports - total path length
+     */
+    private void checkPathLength()
+    {
+        // init
+        int maxPathLength = n;
+        int totalPathLength = 0;
+
+        X509Certificate cert = null;
+
+        int i;
+        for (int index = certs.size() - 1; index > 0; index--)
+        {
+            i = n - index;
+
+            cert = (X509Certificate) certs.get(index);
+
+            // l)
+
+            if (!isSelfIssued(cert))
+            {
+                if (maxPathLength <= 0)
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.pathLenghtExtended");
+                    addError(msg);
+                }
+                maxPathLength--;
+                totalPathLength++;
+            }
+
+            // m)
+
+            BasicConstraints bc;
+            try
+            {
+                bc = BasicConstraints.getInstance(getExtensionValue(cert,
+                        BASIC_CONSTRAINTS));
+            }
+            catch (AnnotatedException ae)
+            {
+                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.processLengthConstError");
+                addError(msg,index);
+                bc = null;
+            }
+
+            if (bc != null)
+            {
+                BigInteger _pathLengthConstraint = bc.getPathLenConstraint();
+
+                if (_pathLengthConstraint != null)
+                {
+                    int _plc = _pathLengthConstraint.intValue();
+
+                    if (_plc < maxPathLength)
+                    {
+                        maxPathLength = _plc;
+                    }
+                }
+            }
+
+        }
+
+        ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.totalPathLength",
+                new Object[] {new Integer(totalPathLength)});
+        
+        addNotification(msg);
+    }
+
+    /*
+     * checks: - signatures - name chaining - validity of certificates - todo:
+     * if certificate revoked (if specified in the parameters)
+     */
+    private void checkSignatures()
+    {
+        // 1.6.1 - Inputs
+        
+        // d)
+        
+        TrustAnchor trust = null;
+        X500Principal trustPrincipal = null;
+        
+        // validation date
+        {
+            ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certPathValidDate",
+                    new Object[] {validDate, new Date()});
+            addNotification(msg);
+        }
+        
+        // find trust anchors
+        try
+        {
+            X509Certificate cert = (X509Certificate) certs.get(certs.size() - 1);
+            Collection trustColl = getTrustAnchors(cert,pkixParams.getTrustAnchors());
+            if (trustColl.size() > 1)
+            {
+                // conflicting trust anchors                
+                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+                        "CertPathReviewer.conflictingTrustAnchors",
+                        new Object[] {new Integer(trustColl.size()),
+                                      new UntrustedInput(cert.getIssuerX500Principal())});
+                addError(msg);
+            }
+            else if (trustColl.isEmpty())
+            {
+                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+                        "CertPathReviewer.noTrustAnchorFound",
+                        new Object[] {new UntrustedInput(cert.getIssuerX500Principal()),
+                                      new Integer(pkixParams.getTrustAnchors().size())});
+                addError(msg);
+            }
+            else
+            {
+                PublicKey trustPublicKey;
+                trust = (TrustAnchor) trustColl.iterator().next();
+                if (trust.getTrustedCert() != null)
+                {
+                    trustPublicKey = trust.getTrustedCert().getPublicKey();
+                }
+                else
+                {
+                    trustPublicKey = trust.getCAPublicKey();
+                }
+                try
+                {
+                    cert.verify(trustPublicKey);
+                }
+                catch (Exception e)
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.trustButInvalidCert");
+                    addError(msg);
+                    trust = null;
+                }
+            }
+        }
+        catch (CertPathReviewerException cpre)
+        {
+            addError(cpre.getErrorMessage());
+        }
+        
+        if (trust != null)
+        {
+            // get the name of the trustAnchor
+            X509Certificate sign = trust.getTrustedCert();
+            try
+            {
+                if (sign != null)
+                {
+                    trustPrincipal = getSubjectPrincipal(sign);
+                }
+                else
+                {
+                    trustPrincipal = new X500Principal(trust.getCAName());
+                }
+            }
+            catch (IllegalArgumentException ex)
+            {
+                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.trustDNInvalid",
+                        new Object[] {new UntrustedInput(trust.getCAName())});
+                addError(msg);
+            }
+        }
+        
+        // 1.6.2 - Initialization
+        
+        PublicKey workingPublicKey = null;
+        X500Principal workingIssuerName = trustPrincipal;
+        
+        X509Certificate sign = null;
+
+        AlgorithmIdentifier workingAlgId = null;
+        DERObjectIdentifier workingPublicKeyAlgorithm = null;
+        DEREncodable workingPublicKeyParameters = null;
+        
+        if (trust != null)
+        {
+            sign = trust.getTrustedCert();
+            
+            if (sign != null)
+            {
+                workingPublicKey = sign.getPublicKey();
+            }
+            else
+            {
+                workingPublicKey = trust.getCAPublicKey();
+            }
+        
+            try
+            {
+                workingAlgId = getAlgorithmIdentifier(workingPublicKey);
+                workingPublicKeyAlgorithm = workingAlgId.getObjectId();
+                workingPublicKeyParameters = workingAlgId.getParameters();
+            }
+            catch (CertPathValidatorException ex)
+            {
+                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.trustPubKeyError");
+                addError(msg);
+                workingAlgId = null;
+            }
+            
+        }
+
+        // Basic cert checks
+
+        X509Certificate cert = null;
+        int i;
+
+        for (int index = certs.size() - 1; index >= 0; index--)
+        {
+            //
+            // i as defined in the algorithm description
+            //
+            i = n - index;
+
+            //
+            // set certificate to be checked in this round
+            // sign and workingPublicKey and workingIssuerName are set
+            // at the end of the for loop and initialied the
+            // first time from the TrustAnchor
+            //
+            cert = (X509Certificate) certs.get(index);
+
+            // verify signature
+            if (workingPublicKey != null)
+            {
+                try
+                {
+                    cert.verify(workingPublicKey, "BC");
+                }
+                catch (GeneralSecurityException ex)
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.signatureNotVerified",
+                            new Object[] {ex.getMessage(),ex}); 
+                    addError(msg,index);
+                }
+            }
+            else
+            {
+                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.NoIssuerPublicKey");
+                addError(msg,index);
+            }
+
+            // certificate valid?
+            try
+            {
+                cert.checkValidity(validDate);
+            }
+            catch (CertificateNotYetValidException cnve)
+            {
+                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certificateNotYetValid",
+                        new Object[] {cert.getNotBefore()});
+                addError(msg,index);
+            }
+            catch (CertificateExpiredException cee)
+            {
+                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certificateExpired",
+                        new Object[] {cert.getNotAfter()});
+                addError(msg,index);
+            }
+
+            // certificate revoked?
+            if (pkixParams.isRevocationEnabled())
+            {
+                // read crl distribution points extension
+                CRLDistPoint crlDistPoints = null;
+                try
+                {
+                    DERObject crl_dp = getExtensionValue(cert,CRL_DIST_POINTS);
+                    if (crl_dp != null)
+                    {
+                        crlDistPoints = CRLDistPoint.getInstance(crl_dp);
+                    }
+                }
+                catch (AnnotatedException ae)
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlDistPtExtError");
+                    addError(msg,index);
+                }
+
+                // read authority information access extension
+                AuthorityInformationAccess authInfoAcc = null;
+                try
+                {
+                    DERObject auth_info_acc = getExtensionValue(cert,AUTH_INFO_ACCESS);
+                    if (auth_info_acc != null)
+                    {
+                        authInfoAcc = AuthorityInformationAccess.getInstance(auth_info_acc);
+                    }
+                }
+                catch (AnnotatedException ae)
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlAuthInfoAccError");
+                    addError(msg,index);
+                }
+                
+                Vector crlDistPointUrls = getCRLDistUrls(crlDistPoints,authInfoAcc);
+                Vector ocspUrls = getOCSPUrls(authInfoAcc);
+                
+                // add notifications with the crl distribution points
+                
+                // output crl distribution points
+                Iterator urlIt = crlDistPointUrls.iterator();
+                while (urlIt.hasNext())
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlDistPoint",
+                                new Object[] {new UntrustedInput(urlIt.next())});
+                    addNotification(msg,index);
+                }
+                
+                // output ocsp urls
+                urlIt = ocspUrls.iterator();
+                while (urlIt.hasNext())
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.ocspLocation",
+                            new Object[] {new UntrustedInput(urlIt.next())});
+                    addNotification(msg,index);
+                }
+                
+                // TODO also support Netscapes revocation-url and/or OCSP instead of CRLs for revocation checking
+                // check CRLs
+                try 
+                {
+                    checkCRLs(pkixParams, cert, validDate, sign, workingPublicKey, crlDistPointUrls, index);
+                }
+                catch (CertPathReviewerException cpre)
+                {
+                    addError(cpre.getErrorMessage(),index);
+                }
+            }
+
+            // certificate issuer correct
+            if (workingIssuerName != null && !cert.getIssuerX500Principal().equals(workingIssuerName))
+            {
+                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certWrongIssuer",
+                            new Object[] {workingIssuerName.getName(),
+                            cert.getIssuerX500Principal().getName()});
+                addError(msg,index);
+            }
+
+            //
+            // prepare for next certificate
+            //
+            if (i != n)
+            {
+
+                if (cert != null && cert.getVersion() == 1)
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noCACert");
+                    addError(msg,index);
+                }
+
+                // k)
+
+                BasicConstraints bc;
+                try
+                {
+                    bc = BasicConstraints.getInstance(getExtensionValue(cert,
+                            BASIC_CONSTRAINTS));
+                    if (bc != null)
+                    {
+                        if (!bc.isCA())
+                        {
+                            ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noCACert");
+                            addError(msg,index);
+                        }
+                    }
+                    else
+                    {
+                        ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noBasicConstraints");
+                        addError(msg,index);
+                    }
+                }
+                catch (AnnotatedException ae)
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.errorProcesingBC");
+                    addError(msg,index);
+                }
+
+                // n)
+
+                boolean[] _usage = cert.getKeyUsage();
+
+                if ((_usage != null) && !_usage[KEY_CERT_SIGN])
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noCertSign");
+                    addError(msg,index);
+                }
+
+            } // if
+
+            // set signing certificate for next round
+            sign = cert;
+            
+            // c)
+
+            workingIssuerName = cert.getSubjectX500Principal();
+
+            // d)
+
+            workingPublicKey = cert.getPublicKey();
+
+            // e) f)
+
+            try
+            {
+                workingAlgId = getAlgorithmIdentifier(workingPublicKey);
+                workingPublicKeyAlgorithm = workingAlgId.getObjectId();
+                workingPublicKeyParameters = workingAlgId.getParameters();
+            }
+            catch (CertPathValidatorException ex)
+            {
+                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.pubKeyError");
+                addError(msg,index);
+                workingAlgId = null;
+                workingPublicKeyAlgorithm = null;
+                workingPublicKeyParameters = null;
+            }
+
+        } // for
+
+        trustAnchor = trust;
+        subjectPublicKey = workingPublicKey;
+    }
+
+    private void checkPolicy()
+    {
+        //
+        // 6.1.1 Inputs
+        //
+
+        // c) Initial Policy Set
+
+        Set userInitialPolicySet = pkixParams.getInitialPolicies();
+
+        // e) f) g) are part of pkixParams
+
+        //
+        // 6.1.2 Initialization
+        //
+
+        // a) valid policy tree
+
+        List[] policyNodes = new ArrayList[n + 1];
+        for (int j = 0; j < policyNodes.length; j++)
+        {
+            policyNodes[j] = new ArrayList();
+        }
+
+        Set policySet = new HashSet();
+
+        policySet.add(ANY_POLICY);
+
+        PKIXPolicyNode validPolicyTree = new PKIXPolicyNode(new ArrayList(), 0,
+                policySet, null, new HashSet(), ANY_POLICY, false);
+
+        policyNodes[0].add(validPolicyTree);
+
+        // d) explicit policy
+
+        int explicitPolicy;
+        if (pkixParams.isExplicitPolicyRequired())
+        {
+            explicitPolicy = 0;
+        }
+        else
+        {
+            explicitPolicy = n + 1;
+        }
+
+        // e) inhibit any policy
+
+        int inhibitAnyPolicy;
+        if (pkixParams.isAnyPolicyInhibited())
+        {
+            inhibitAnyPolicy = 0;
+        }
+        else
+        {
+            inhibitAnyPolicy = n + 1;
+        }
+
+        // f) policy mapping
+
+        int policyMapping;
+        if (pkixParams.isPolicyMappingInhibited())
+        {
+            policyMapping = 0;
+        }
+        else
+        {
+            policyMapping = n + 1;
+        }
+
+        Set acceptablePolicies = null;
+
+        //
+        // 6.1.3 Basic Certificate processing
+        //
+
+        X509Certificate cert = null;
+        int index;
+        int i;
+
+        try 
+        {
+            for (index = certs.size() - 1; index >= 0; index--)
+            {
+                // i as defined in the algorithm description
+                i = n - index;
+    
+                // set certificate to be checked in this round
+                cert = (X509Certificate) certs.get(index);
+    
+                // d) process policy information
+    
+                ASN1Sequence certPolicies;
+                try 
+                {
+                    certPolicies = (ASN1Sequence) getExtensionValue(
+                        cert, CERTIFICATE_POLICIES);
+                }
+                catch (AnnotatedException ae)
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyExtError");
+                    throw new CertPathReviewerException(msg,ae,certPath,index);
+                }
+                if (certPolicies != null && validPolicyTree != null)
+                {
+
+                    // d) 1)
+
+                    Enumeration e = certPolicies.getObjects();
+                    Set pols = new HashSet();
+
+                    while (e.hasMoreElements())
+                    {
+                        PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement());
+                        DERObjectIdentifier pOid = pInfo.getPolicyIdentifier();
+
+                        pols.add(pOid.getId());
+
+                        if (!ANY_POLICY.equals(pOid.getId()))
+                        {
+                            Set pq;
+                            try
+                            {
+                                pq = getQualifierSet(pInfo.getPolicyQualifiers());
+                            }
+                            catch (CertPathValidatorException cpve)
+                            {
+                                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyQualifierError");
+                                throw new CertPathReviewerException(msg,cpve,certPath,index);
+                            }
+
+                            boolean match = processCertD1i(i, policyNodes, pOid, pq);
+
+                            if (!match)
+                            {
+                                processCertD1ii(i, policyNodes, pOid, pq);
+                            }
+                        }
+                    }
+
+                    if (acceptablePolicies == null || acceptablePolicies.contains(ANY_POLICY))
+                    {
+                        acceptablePolicies = pols;
+                    }
+                    else
+                    {
+                        Iterator it = acceptablePolicies.iterator();
+                        Set t1 = new HashSet();
+
+                        while (it.hasNext())
+                        {
+                            Object o = it.next();
+
+                            if (pols.contains(o))
+                            {
+                                t1.add(o);
+                            }
+                        }
+
+                        acceptablePolicies = t1;
+                    }
+
+                    // d) 2)
+
+                    if ((inhibitAnyPolicy > 0) || ((i < n) && isSelfIssued(cert)))
+                    {
+                        e = certPolicies.getObjects();
+
+                        while (e.hasMoreElements())
+                        {
+                            PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement());
+
+                            if (ANY_POLICY.equals(pInfo.getPolicyIdentifier().getId()))
+                            {
+                                Set _apq;
+                                try
+                                {
+                                    _apq = getQualifierSet(pInfo.getPolicyQualifiers());
+                                }
+                                catch (CertPathValidatorException cpve)
+                                {
+                                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyQualifierError");
+                                    throw new CertPathReviewerException(msg,cpve,certPath,index);
+                                }
+                                List _nodes = policyNodes[i - 1];
+
+                                for (int k = 0; k < _nodes.size(); k++)
+                                {
+                                    PKIXPolicyNode _node = (PKIXPolicyNode) _nodes.get(k);
+
+                                    Iterator _policySetIter = _node.getExpectedPolicies().iterator();
+                                    while (_policySetIter.hasNext())
+                                    {
+                                        Object _tmp = _policySetIter.next();
+
+                                        String _policy;
+                                        if (_tmp instanceof String)
+                                        {
+                                            _policy = (String) _tmp;
+                                        }
+                                        else if (_tmp instanceof DERObjectIdentifier)
+                                        {
+                                            _policy = ((DERObjectIdentifier) _tmp).getId();
+                                        }
+                                        else
+                                        {
+                                            continue;
+                                        }
+
+                                        boolean _found = false;
+                                        Iterator _childrenIter = _node
+                                                .getChildren();
+
+                                        while (_childrenIter.hasNext())
+                                        {
+                                            PKIXPolicyNode _child = (PKIXPolicyNode) _childrenIter.next();
+
+                                            if (_policy.equals(_child.getValidPolicy()))
+                                            {
+                                                _found = true;
+                                            }
+                                        }
+
+                                        if (!_found)
+                                        {
+                                            Set _newChildExpectedPolicies = new HashSet();
+                                            _newChildExpectedPolicies.add(_policy);
+
+                                            PKIXPolicyNode _newChild = new PKIXPolicyNode(
+                                                    new ArrayList(), i,
+                                                    _newChildExpectedPolicies,
+                                                    _node, _apq, _policy, false);
+                                            _node.addChild(_newChild);
+                                            policyNodes[i].add(_newChild);
+                                        }
+                                    }
+                                }
+                                break;
+                            }
+                        }
+                    }
+
+                    //
+                    // (d) (3)
+                    //
+                    for (int j = (i - 1); j >= 0; j--)
+                    {
+                        List nodes = policyNodes[j];
+
+                        for (int k = 0; k < nodes.size(); k++)
+                        {
+                            PKIXPolicyNode node = (PKIXPolicyNode) nodes.get(k);
+                            if (!node.hasChildren())
+                            {
+                                validPolicyTree = removePolicyNode(
+                                        validPolicyTree, policyNodes, node);
+                                if (validPolicyTree == null)
+                                {
+                                    break;
+                                }
+                            }
+                        }
+                    }
+
+                    //
+                    // d (4)
+                    //
+                    Set criticalExtensionOids = cert.getCriticalExtensionOIDs();
+
+                    if (criticalExtensionOids != null)
+                    {
+                        boolean critical = criticalExtensionOids.contains(CERTIFICATE_POLICIES);
+
+                        List nodes = policyNodes[i];
+                        for (int j = 0; j < nodes.size(); j++)
+                        {
+                            PKIXPolicyNode node = (PKIXPolicyNode) nodes.get(j);
+                            node.setCritical(critical);
+                        }
+                    }
+
+                }
+                
+                // e)
+                
+                if (certPolicies == null) 
+                {
+                    validPolicyTree = null;
+                }
+                
+                // f)
+                
+                if (explicitPolicy <= 0 && validPolicyTree == null)
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noValidPolicyTree");
+                    throw new CertPathReviewerException(msg);
+                }
+    
+                //
+                // 6.1.4 preparation for next Certificate
+                //
+    
+                if (i != n)
+                {
+                    
+                    // a)
+                    
+                    DERObject pm;
+                    try
+                    {
+                        pm = getExtensionValue(cert, POLICY_MAPPINGS);
+                    }
+                    catch (AnnotatedException ae)
+                    {
+                        ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyMapExtError");
+                        throw new CertPathReviewerException(msg,ae,certPath,index);
+                    }
+                    
+                    if (pm != null) 
+                    {
+                        ASN1Sequence mappings = (ASN1Sequence) pm;
+                        for (int j = 0; j < mappings.size(); j++) 
+                        {
+                            ASN1Sequence mapping = (ASN1Sequence) mappings.getObjectAt(j);
+                            DERObjectIdentifier ip_id = (DERObjectIdentifier) mapping.getObjectAt(0);
+                            DERObjectIdentifier sp_id = (DERObjectIdentifier) mapping.getObjectAt(1);
+                            if (ANY_POLICY.equals(ip_id.getId())) 
+                            {
+                                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.invalidPolicyMapping");
+                                throw new CertPathReviewerException(msg,certPath,index);
+                            }
+                            if (ANY_POLICY.equals(sp_id.getId()))
+                            {
+                                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.invalidPolicyMapping");
+                                throw new CertPathReviewerException(msg,certPath,index);
+                            }
+                        }
+                    }
+                    
+                    // b)
+                    
+                    if (pm != null)
+                    {
+                        ASN1Sequence mappings = (ASN1Sequence)pm;
+                        Map m_idp = new HashMap();
+                        Set s_idp = new HashSet();
+                        
+                        for (int j = 0; j < mappings.size(); j++)
+                        {
+                            ASN1Sequence mapping = (ASN1Sequence)mappings.getObjectAt(j);
+                            String id_p = ((DERObjectIdentifier)mapping.getObjectAt(0)).getId();
+                            String sd_p = ((DERObjectIdentifier)mapping.getObjectAt(1)).getId();
+                            Set tmp;
+                            
+                            if (!m_idp.containsKey(id_p))
+                            {
+                                tmp = new HashSet();
+                                tmp.add(sd_p);
+                                m_idp.put(id_p, tmp);
+                                s_idp.add(id_p);
+                            }
+                            else
+                            {
+                                tmp = (Set)m_idp.get(id_p);
+                                tmp.add(sd_p);
+                            }
+                        }
+    
+                        Iterator it_idp = s_idp.iterator();
+                        while (it_idp.hasNext())
+                        {
+                            String id_p = (String)it_idp.next();
+                            
+                            //
+                            // (1)
+                            //
+                            if (policyMapping > 0)
+                            {
+                                try
+                                {
+                                    prepareNextCertB1(i,policyNodes,id_p,m_idp,cert);
+                                }
+                                catch (AnnotatedException ae)
+                                {
+                                    // error processing certificate policies extension
+                                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyExtError");
+                                    throw new CertPathReviewerException(msg,ae,certPath,index);
+                                }
+                                catch (CertPathValidatorException cpve)
+                                {
+                                    // error building qualifier set
+                                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyQualifierError");
+                                    throw new CertPathReviewerException(msg,cpve,certPath,index);
+                                }
+                                
+                                //
+                                // (2)
+                                // 
+                            }
+                            else if (policyMapping <= 0)
+                            {
+                                validPolicyTree = prepareNextCertB2(i,policyNodes,id_p,validPolicyTree);
+                            }
+                            
+                        }
+                    }
+                    
+                    //
+                    // h)
+                    //
+                    
+                    if (!isSelfIssued(cert)) 
+                    {
+                        
+                        // (1)
+                        if (explicitPolicy != 0)
+                        {
+                            explicitPolicy--;
+                        }
+                        
+                        // (2)
+                        if (policyMapping != 0)
+                        {
+                            policyMapping--;
+                        }
+                        
+                        // (3)
+                        if (inhibitAnyPolicy != 0)
+                        {
+                            inhibitAnyPolicy--;
+                        }
+                        
+                    }
+    
+                    //
+                    // i)
+                    //
+                    
+                    try
+                    {
+                        ASN1Sequence pc = (ASN1Sequence) getExtensionValue(cert,POLICY_CONSTRAINTS);
+                        if (pc != null)
+                        {
+                            Enumeration policyConstraints = pc.getObjects();
+                            
+                            while (policyConstraints.hasMoreElements())
+                            {
+                                ASN1TaggedObject constraint = (ASN1TaggedObject) policyConstraints.nextElement();
+                                int tmpInt; 
+                                
+                                switch (constraint.getTagNo())
+                                {
+                                case 0:
+                                    tmpInt = DERInteger.getInstance(constraint).getValue().intValue();
+                                    if (tmpInt < explicitPolicy)
+                                    {
+                                        explicitPolicy = tmpInt;
+                                    }
+                                    break;
+                                case 1:
+                                    tmpInt = DERInteger.getInstance(constraint).getValue().intValue();
+                                    if (tmpInt < policyMapping)
+                                    {
+                                        policyMapping = tmpInt;
+                                    }
+                                break;
+                                }
+                            }
+                        }
+                    }
+                    catch (AnnotatedException ae)
+                    {
+                        ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyConstExtError");
+                        throw new CertPathReviewerException(msg,certPath,index);
+                    }
+    
+                    //
+                    // j)
+                    //
+                    
+                    try 
+                    {
+                        DERInteger iap = (DERInteger)getExtensionValue(cert, INHIBIT_ANY_POLICY);
+                        
+                        if (iap != null)
+                        {
+                            int _inhibitAnyPolicy = iap.getValue().intValue();
+                        
+                            if (_inhibitAnyPolicy < inhibitAnyPolicy)
+                            {
+                                inhibitAnyPolicy = _inhibitAnyPolicy;
+                            }
+                        }
+                    }
+                    catch (AnnotatedException ae)
+                    {
+                        ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyInhibitExtError");
+                        throw new CertPathReviewerException(msg,certPath,index);
+                    }
+                }
+    
+            }
+    
+            //
+            // 6.1.5 Wrap up
+            //
+    
+            //
+            // a)
+            //
+            
+            if (!isSelfIssued(cert) && explicitPolicy > 0) 
+            {
+                explicitPolicy--;
+            }
+    
+            //
+            // b)
+            //
+            
+            try
+            {
+                ASN1Sequence pc = (ASN1Sequence) getExtensionValue(cert, POLICY_CONSTRAINTS);
+                if (pc != null)
+                {
+                    Enumeration policyConstraints = pc.getObjects();
+        
+                    while (policyConstraints.hasMoreElements())
+                    {
+                        ASN1TaggedObject    constraint = (ASN1TaggedObject)policyConstraints.nextElement();
+                        switch (constraint.getTagNo())
+                        {
+                        case 0:
+                            int tmpInt = DERInteger.getInstance(constraint).getValue().intValue();
+                            if (tmpInt == 0)
+                            {
+                                explicitPolicy = 0;
+                            }
+                            break;
+                        }
+                    }
+                }
+            }
+            catch (AnnotatedException e)
+            {
+                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyConstExtError");
+                throw new CertPathReviewerException(msg,certPath,index);
+            }
+            
+            
+            //
+            // (g)
+            //
+            PKIXPolicyNode intersection;
+            
+    
+            //
+            // (g) (i)
+            //
+            if (validPolicyTree == null)
+            { 
+                if (pkixParams.isExplicitPolicyRequired())
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.explicitPolicy");
+                    throw new CertPathReviewerException(msg,certPath,index);
+                }
+                intersection = null;
+            }
+            else if (isAnyPolicy(userInitialPolicySet)) // (g) (ii)
+            {
+                if (pkixParams.isExplicitPolicyRequired())
+                {
+                    if (acceptablePolicies.isEmpty())
+                    {
+                        ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.explicitPolicy");
+                        throw new CertPathReviewerException(msg,certPath,index);
+                    }
+                    else
+                    {
+                        Set _validPolicyNodeSet = new HashSet();
+                        
+                        for (int j = 0; j < policyNodes.length; j++)
+                        {
+                            List      _nodeDepth = policyNodes[j];
+                            
+                            for (int k = 0; k < _nodeDepth.size(); k++)
+                            {
+                                PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k);
+                                
+                                if (ANY_POLICY.equals(_node.getValidPolicy()))
+                                {
+                                    Iterator _iter = _node.getChildren();
+                                    while (_iter.hasNext())
+                                    {
+                                        _validPolicyNodeSet.add(_iter.next());
+                                    }
+                                }
+                            }
+                        }
+                        
+                        Iterator _vpnsIter = _validPolicyNodeSet.iterator();
+                        while (_vpnsIter.hasNext())
+                        {
+                            PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next();
+                            String _validPolicy = _node.getValidPolicy();
+                            
+                            if (!acceptablePolicies.contains(_validPolicy))
+                            {
+                                //validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, _node);
+                            }
+                        }
+                        if (validPolicyTree != null)
+                        {
+                            for (int j = (n - 1); j >= 0; j--)
+                            {
+                                List      nodes = policyNodes[j];
+                                
+                                for (int k = 0; k < nodes.size(); k++)
+                                {
+                                    PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+                                    if (!node.hasChildren())
+                                    {
+                                        validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, node);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+    
+                intersection = validPolicyTree;
+            }
+            else
+            {
+                //
+                // (g) (iii)
+                //
+                // This implementation is not exactly same as the one described in RFC3280.
+                // However, as far as the validation result is concerned, both produce 
+                // adequate result. The only difference is whether AnyPolicy is remain 
+                // in the policy tree or not. 
+                //
+                // (g) (iii) 1
+                //
+                Set _validPolicyNodeSet = new HashSet();
+                
+                for (int j = 0; j < policyNodes.length; j++)
+                {
+                    List      _nodeDepth = policyNodes[j];
+                    
+                    for (int k = 0; k < _nodeDepth.size(); k++)
+                    {
+                        PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k);
+                        
+                        if (ANY_POLICY.equals(_node.getValidPolicy()))
+                        {
+                            Iterator _iter = _node.getChildren();
+                            while (_iter.hasNext())
+                            {
+                                PKIXPolicyNode _c_node = (PKIXPolicyNode)_iter.next();
+                                if (!ANY_POLICY.equals(_c_node.getValidPolicy()))
+                                {
+                                    _validPolicyNodeSet.add(_c_node);
+                                }
+                            }
+                        }
+                    }
+                }
+                
+                //
+                // (g) (iii) 2
+                //
+                Iterator _vpnsIter = _validPolicyNodeSet.iterator();
+                while (_vpnsIter.hasNext())
+                {
+                    PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next();
+                    String _validPolicy = _node.getValidPolicy();
+    
+                    if (!userInitialPolicySet.contains(_validPolicy))
+                    {
+                        validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, _node);
+                    }
+                }
+                
+                //
+                // (g) (iii) 4
+                //
+                if (validPolicyTree != null)
+                {
+                    for (int j = (n - 1); j >= 0; j--)
+                    {
+                        List      nodes = policyNodes[j];
+                        
+                        for (int k = 0; k < nodes.size(); k++)
+                        {
+                            PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+                            if (!node.hasChildren())
+                            {
+                                validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, node);
+                            }
+                        }
+                    }
+                }
+                
+                intersection = validPolicyTree;
+            }
+     
+            if ((explicitPolicy <= 0) && (intersection == null))
+            {
+                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.invalidPolicy");
+                throw new CertPathReviewerException(msg);
+            }
+            
+            validPolicyTree = intersection;
+        }
+        catch (CertPathReviewerException cpre)
+        {
+            addError(cpre.getErrorMessage(),cpre.getIndex());
+            validPolicyTree = null;
+        }
+    }
+
+    private void checkCriticalExtensions()
+    {
+        //      
+        // initialise CertPathChecker's
+        //
+        List  pathCheckers = pkixParams.getCertPathCheckers();
+        Iterator certIter = pathCheckers.iterator();
+        
+        try
+        {
+            try
+            {
+                while (certIter.hasNext())
+                {
+                    ((PKIXCertPathChecker)certIter.next()).init(false);
+                }
+            }
+            catch (CertPathValidatorException cpve)
+            {
+                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certPathCheckerError",
+                        new Object[] {cpve.getMessage(),cpve});
+                throw new CertPathReviewerException(msg,cpve);
+            }
+            
+            //
+            // process critical extesions for each certificate
+            //
+            
+            X509Certificate cert = null;
+            
+            int index;
+            
+            for (index = certs.size()-1; index >= 0; index--)
+            {
+                cert = (X509Certificate) certs.get(index);
+                
+                Set criticalExtensions = new HashSet(cert.getCriticalExtensionOIDs());
+                // remove already processed extensions
+                criticalExtensions.remove(KEY_USAGE);
+                criticalExtensions.remove(CERTIFICATE_POLICIES);
+                criticalExtensions.remove(POLICY_MAPPINGS);
+                criticalExtensions.remove(INHIBIT_ANY_POLICY);
+                criticalExtensions.remove(ISSUING_DISTRIBUTION_POINT);
+                criticalExtensions.remove(DELTA_CRL_INDICATOR);
+                criticalExtensions.remove(POLICY_CONSTRAINTS);
+                criticalExtensions.remove(BASIC_CONSTRAINTS);
+                criticalExtensions.remove(SUBJECT_ALTERNATIVE_NAME);
+                criticalExtensions.remove(NAME_CONSTRAINTS);
+                
+                // process qcStatements extension
+                if (criticalExtensions.contains(QC_STATEMENT))
+                {
+                    if (processQcStatements(cert,index)) 
+                    {
+                        criticalExtensions.remove(QC_STATEMENT);
+                    }
+                }
+                
+                Iterator tmpIter = pathCheckers.iterator();
+                while (tmpIter.hasNext())
+                {
+                    try
+                    {
+                        ((PKIXCertPathChecker)tmpIter.next()).check(cert, criticalExtensions);
+                    }
+                    catch (CertPathValidatorException e)
+                    {
+                        ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.criticalExtensionError",
+                                new Object[] {e.getMessage(),e});
+                        throw new CertPathReviewerException(msg,e.getCause(),certPath,index);
+                    }
+                }
+                if (!criticalExtensions.isEmpty())
+                {
+                    ErrorBundle msg;
+                    if (criticalExtensions.size() == 1)
+                    {
+                        msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.unknownCriticalExt",
+                                new Object[] {criticalExtensions.iterator().next()});
+                    }
+                    else
+                    {
+                        msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.unknownCriticalExts",
+                                new Object[] {new UntrustedInput(criticalExtensions)});
+                    }
+                    throw new CertPathReviewerException(msg,certPath,index);
+                }
+            }
+        }
+        catch (CertPathReviewerException cpre)
+        {
+            addError(cpre.getErrorMessage(),cpre.getIndex());
+        }
+    }
+    
+    private boolean processQcStatements(
+            X509Certificate cert,
+            int index)
+    {   
+        try
+        {
+            boolean unknownStatement = false;
+            
+            ASN1Sequence qcSt = (ASN1Sequence) getExtensionValue(cert,QC_STATEMENT);
+            for (int j = 0; j < qcSt.size(); j++)
+            {
+                QCStatement stmt = QCStatement.getInstance(qcSt.getObjectAt(j));
+                if (QCStatement.id_etsi_qcs_QcCompliance.equals(stmt.getStatementId()))
+                {
+                    // process statement - just write a notification that the certificate contains this statement
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcEuCompliance");
+                    addNotification(msg,index);
+                }
+                else if (QCStatement.id_qcs_pkixQCSyntax_v1.equals(stmt.getStatementId()))
+                {
+                    // process statement - just recognize the statement
+                }
+                else if (QCStatement.id_etsi_qcs_QcSSCD.equals(stmt.getStatementId()))
+                {
+                    // process statement - just write a notification that the certificate contains this statement
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcSSCD");
+                    addNotification(msg,index);
+                }
+                else if (QCStatement.id_etsi_qcs_LimiteValue.equals(stmt.getStatementId()))
+                {
+                    // process statement - write a notification containing the limit value
+                    MonetaryValue limit = MonetaryValue.getInstance(stmt.getStatementInfo());
+                    Iso4217CurrencyCode currency = limit.getCurrency();
+                    double value = limit.getAmount().doubleValue() * Math.pow(10,limit.getExponent().doubleValue());
+                    ErrorBundle msg;
+                    if (limit.getCurrency().isAlphabetic())
+                    {
+                        msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcLimitValueAlpha",
+                                new Object[] {limit.getCurrency().getAlphabetic(),
+                                              new Double(value),
+                                              limit});
+                    }
+                    else
+                    {
+                        msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcLimitValueNum",
+                                new Object[] {new Integer(limit.getCurrency().getNumeric()),
+                                              new Double(value),
+                                              limit});
+                    }
+                    addNotification(msg,index);
+                }
+                else
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcUnknownStatement",
+                            new Object[] {stmt.getStatementId(),new UntrustedInput(stmt)});
+                    addNotification(msg,index);
+                    unknownStatement = true;
+                }
+            }
+            
+            return !unknownStatement;
+        }
+        catch (AnnotatedException ae)
+        {
+            ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcStatementExtError");
+            addError(msg,index);
+        }
+        
+        return false;
+    }
+    
+    private String IPtoString(byte[] ip)
+    {
+        String result;
+        try
+        {
+            result = InetAddress.getByAddress(ip).getHostAddress();
+        }
+        catch (Exception e)
+        {
+            StringBuffer b = new StringBuffer();
+            
+            for (int i = 0; i != ip.length; i++)
+            {
+                b.append(Integer.toHexString(ip[i] & 0xff));
+                b.append(' ');
+            }
+            
+            result = b.toString();
+        }
+        
+        return result;
+    }
+    
+    private void checkCRLs(
+            PKIXParameters paramsPKIX,
+            X509Certificate cert,
+            Date validDate,
+            X509Certificate sign,
+            PublicKey workingPublicKey,
+            Vector crlDistPointUrls,
+            int index) 
+        throws CertPathReviewerException
+    {
+        X509CRLSelector crlselect;
+        crlselect = new X509CRLSelector();
+        
+        try
+        {
+            crlselect.addIssuerName(getEncodedIssuerPrincipal(cert).getEncoded());
+        }
+        catch (IOException e)
+        {
+            ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlIssuerException");
+            throw new CertPathReviewerException(msg,e);
+        }
+    
+        crlselect.setCertificateChecking(cert);
+    
+        Iterator crl_iter;
+        try 
+        {
+            Collection crl_coll = findCRLs(crlselect, paramsPKIX.getCertStores());
+            crl_iter = crl_coll.iterator();
+            
+            if (crl_coll.isEmpty())
+            {
+                // notifcation - no local crls found
+                crl_coll = findCRLs(new X509CRLSelector(),paramsPKIX.getCertStores());
+                Iterator it = crl_coll.iterator();
+                List nonMatchingCrlNames = new ArrayList();
+                while (it.hasNext())
+                {
+                    nonMatchingCrlNames.add(((X509CRL) it.next()).getIssuerX500Principal());
+                }
+                int numbOfCrls = nonMatchingCrlNames.size();
+                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+                        "CertPathReviewer.noCrlInCertstore",
+                        new Object[] {new UntrustedInput(crlselect.getIssuers()),
+                                      new UntrustedInput(nonMatchingCrlNames),
+                                      new Integer(numbOfCrls)});
+                addNotification(msg,index);
+            }
+
+        }
+        catch (AnnotatedException ae)
+        {
+            ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlExtractionError",
+                    new Object[] {ae.getCause().getMessage(),ae.getCause()});
+            addError(msg,index);
+            crl_iter = new ArrayList().iterator();
+        }
+        boolean validCrlFound = false;
+        X509CRL crl = null;
+        while (crl_iter.hasNext())
+        {
+            crl = (X509CRL)crl_iter.next();
+            
+            if (crl.getNextUpdate() == null
+                || new Date().before(crl.getNextUpdate()))
+            {
+                validCrlFound = true;
+                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+                        "CertPathReviewer.localValidCRL",
+                        new Object[] {crl.getThisUpdate(),crl.getNextUpdate()});
+                addNotification(msg,index);
+                break;
+            }
+            else
+            {
+                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+                        "CertPathReviewer.localInvalidCRL",
+                        new Object[] {crl.getThisUpdate(),crl.getNextUpdate()});
+                addNotification(msg,index);
+            }
+        }
+        
+        // if no valid crl was found in the CertStores try to get one from a
+        // crl distribution point
+        if (!validCrlFound)
+        {
+            X509CRL onlineCRL = null;
+            Iterator urlIt = crlDistPointUrls.iterator();
+            while (urlIt.hasNext())
+            {
+                try
+                {
+                    String location = (String) urlIt.next();
+                    onlineCRL = getCRL(location);
+                    if (onlineCRL != null)
+                    {
+                        if (onlineCRL.getNextUpdate() == null
+                            || new Date().before(onlineCRL.getNextUpdate()))
+                        {
+                            validCrlFound = true;
+                            ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+                                    "CertPathReviewer.onlineValidCRL",
+                                    new Object[] {onlineCRL.getThisUpdate(),
+                                                  onlineCRL.getNextUpdate(),
+                                                  new UntrustedInput(location)});
+                            addNotification(msg,index);
+                            crl = onlineCRL;
+                            break;
+                        }
+                        else
+                        {
+                            ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+                                    "CertPathReviewer.onlineInvalidCRL",
+                                    new Object[] {onlineCRL.getThisUpdate(),
+                                                  onlineCRL.getNextUpdate(),
+                                                  new UntrustedInput(location)});
+                            addNotification(msg,index);
+                        }
+                    }
+                }
+                catch (CertPathReviewerException cpre)
+                {
+                    addNotification(cpre.getErrorMessage(),index);
+                }
+            }
+        }
+        
+        // check the crl
+        X509CRLEntry crl_entry;
+        if (crl != null)
+        {
+            if (sign != null)
+            {
+                boolean[] keyusage = sign.getKeyUsage();
+
+                if (keyusage != null
+                    && (keyusage.length < 7 || !keyusage[CRL_SIGN]))
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noCrlSigningPermited");
+                    throw new CertPathReviewerException(msg);
+                }
+            }
+
+            if (workingPublicKey != null)
+            {
+                try
+                {
+                    crl.verify(workingPublicKey, "BC");
+                }
+                catch (Exception e)
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlVerifyFailed");
+                    throw new CertPathReviewerException(msg,e);
+                }
+            }
+            else // issuer public key not known
+            {
+                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlNoIssuerPublicKey");
+                throw new CertPathReviewerException(msg);
+            }
+
+            crl_entry = crl.getRevokedCertificate(cert.getSerialNumber());
+            if (crl_entry != null)
+            {
+                String reason = null;
+                
+                if (crl_entry.hasExtensions())
+                {
+                    DEREnumerated reasonCode;
+                    try
+                    {
+                        reasonCode = DEREnumerated.getInstance(getExtensionValue(crl_entry, X509Extensions.ReasonCode.getId()));
+                    }
+                    catch (AnnotatedException ae)
+                    {
+                        ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlReasonExtError");
+                        throw new CertPathReviewerException(msg,ae);
+                    }
+                    if (reasonCode != null)
+                    {
+                        reason = crlReasons[reasonCode.getValue().intValue()];
+                    }
+                }
+                
+                // FIXME reason not i18n
+                
+                if (!validDate.before(crl_entry.getRevocationDate()))
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certRevoked",
+                            new Object[] {crl_entry.getRevocationDate(),reason});
+                    throw new CertPathReviewerException(msg);
+                }
+                else // cert was revoked after validation date
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.revokedAfterValidation",
+                            new Object[] {crl_entry.getRevocationDate(),reason});
+                    addNotification(msg,index);
+                }
+            }
+            else // cert is not revoked
+            {
+                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.notRevoked");
+                addNotification(msg,index);
+            }
+            
+            //
+            // warn if a new crl is available
+            //
+            if (crl.getNextUpdate() != null && crl.getNextUpdate().before(new Date()))
+            {
+                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlUpdateAvailable",
+                        new Object[] {crl.getNextUpdate()});
+                addNotification(msg,index);
+            }
+            
+            //
+            // check the DeltaCRL indicator, base point and the issuing distribution point
+            //
+            DERObject idp;
+            try
+            {
+                idp = getExtensionValue(crl, ISSUING_DISTRIBUTION_POINT);
+            }
+            catch (AnnotatedException ae)
+            {
+                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.distrPtExtError");
+                throw new CertPathReviewerException(msg);
+            }
+            DERObject dci;
+            try
+            {
+                dci = getExtensionValue(crl, DELTA_CRL_INDICATOR);
+            }
+            catch (AnnotatedException ae)
+            {
+                ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.deltaCrlExtError");
+                throw new CertPathReviewerException(msg);
+            }
+
+            if (dci != null)
+            {
+                X509CRLSelector baseSelect = new X509CRLSelector();
+
+                try
+                {
+                    baseSelect.addIssuerName(getIssuerPrincipal(crl).getEncoded());
+                }
+                catch (IOException e)
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlIssuerException");
+                    throw new CertPathReviewerException(msg,e);
+                }
+
+                baseSelect.setMinCRLNumber(((DERInteger)dci).getPositiveValue());
+                try
+                {
+                    baseSelect.setMaxCRLNumber(((DERInteger)getExtensionValue(crl, CRL_NUMBER)).getPositiveValue().subtract(BigInteger.valueOf(1)));
+                }
+                catch (AnnotatedException ae)
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlNbrExtError");
+                    throw new CertPathReviewerException(msg,ae);
+                }
+                
+                boolean  foundBase = false;
+                Iterator it;
+                try 
+                {
+                    it  = findCRLs(baseSelect, paramsPKIX.getCertStores()).iterator();
+                }
+                catch (AnnotatedException ae)
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlExtractionError");
+                    throw new CertPathReviewerException(msg,ae);
+                }
+                while (it.hasNext())
+                {
+                    X509CRL base = (X509CRL)it.next();
+
+                    DERObject baseIdp;
+                    try
+                    {
+                        baseIdp = getExtensionValue(base, ISSUING_DISTRIBUTION_POINT);
+                    }
+                    catch (AnnotatedException ae)
+                    {
+                        ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.distrPtExtError");
+                        throw new CertPathReviewerException(msg,ae);
+                    }
+                    
+                    if (idp == null)
+                    {
+                        if (baseIdp == null)
+                        {
+                            foundBase = true;
+                            break;
+                        }
+                    }
+                    else
+                    {
+                        if (idp.equals(baseIdp))
+                        {
+                            foundBase = true;
+                            break;
+                        }
+                    }
+                }
+                
+                if (!foundBase)
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noBaseCRL");
+                    throw new CertPathReviewerException(msg);
+                }
+            }
+
+            if (idp != null)
+            {
+                IssuingDistributionPoint    p = IssuingDistributionPoint.getInstance(idp);
+                BasicConstraints bc = null;
+                try
+                {
+                    bc = BasicConstraints.getInstance(getExtensionValue(cert, BASIC_CONSTRAINTS));
+                }
+                catch (AnnotatedException ae)
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlBCExtError");
+                    throw new CertPathReviewerException(msg,ae);
+                }
+                
+                if (p.onlyContainsUserCerts() && (bc != null && bc.isCA()))
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlOnlyUserCert");
+                    throw new CertPathReviewerException(msg);
+                }
+                
+                if (p.onlyContainsCACerts() && (bc == null || !bc.isCA()))
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlOnlyCaCert");
+                    throw new CertPathReviewerException(msg);
+                }
+                
+                if (p.onlyContainsAttributeCerts())
+                {
+                    ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlOnlyAttrCert");
+                    throw new CertPathReviewerException(msg);
+                }
+            }
+        }
+        
+        if (!validCrlFound)
+        {
+            ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noValidCrlFound");
+            throw new CertPathReviewerException(msg);
+        }
+    
+    }
+    
+    private Vector getCRLDistUrls(CRLDistPoint crlDistPoints, AuthorityInformationAccess authInfoAcc)
+    {
+        Vector urls = new Vector();
+        
+        if (crlDistPoints != null)
+        {
+            DistributionPoint[] distPoints = crlDistPoints.getDistributionPoints();
+            for (int i = 0; i < distPoints.length; i++)
+            {
+                DistributionPointName dp_name = distPoints[i].getDistributionPoint();
+                if (dp_name.getType() == DistributionPointName.FULL_NAME)
+                {
+                    GeneralName[] generalNames = GeneralNames.getInstance(dp_name.getName()).getNames();
+                    for (int j = 0; j < generalNames.length; j++)
+                    {
+                        if (generalNames[j].getTagNo() == GeneralName.uniformResourceIdentifier)
+                        {
+                            String url = ((DERIA5String) generalNames[j].getName()).getString();
+                            urls.add(url);
+                        }
+                    }
+                }
+            }
+        }
+        
+        if (authInfoAcc != null)
+        {
+            AccessDescription[] ads = authInfoAcc.getAccessDescriptions();
+            for (int i = 0; i < ads.length; i++)
+            {
+                if (ads[i].getAccessMethod().equals(AccessDescription.id_ad_caIssuers))
+                {
+                    GeneralName name = ads[i].getAccessLocation();
+                    if (name.getTagNo() ==  GeneralName.uniformResourceIdentifier)
+                    {
+                        String url = ((DERIA5String) name.getName()).getString();
+                        urls.add(url);
+                    }
+                }
+            }
+        }
+        
+        return urls;
+    }
+    
+    private Vector getOCSPUrls(AuthorityInformationAccess authInfoAccess)
+    {
+        Vector urls = new Vector();
+        
+        if (authInfoAccess != null)
+        {
+            AccessDescription[] ads = authInfoAccess.getAccessDescriptions();
+            for (int i = 0; i < ads.length; i++)
+            {
+                if (ads[i].getAccessMethod().equals(AccessDescription.id_ad_ocsp))
+                {
+                    GeneralName name = ads[i].getAccessLocation();
+                    if (name.getTagNo() == GeneralName.uniformResourceIdentifier)
+                    {
+                        String url = ((DERIA5String) name.getName()).getString();
+                        urls.add(url);
+                    }
+                }
+            }
+        }
+        
+        return urls;
+    }
+    
+    private X509CRL getCRL(String location) throws CertPathReviewerException
+    {
+        X509CRL result = null;
+        try
+        {
+            URL url = new URL(location);
+            
+            if (url.getProtocol().equals("http") || url.getProtocol().equals("https"))
+            {
+                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+                conn.setUseCaches(false);
+                conn.setConnectTimeout(2000);
+                conn.setDoInput(true);
+                conn.connect();
+                if (conn.getResponseCode() == HttpURLConnection.HTTP_OK)
+                {
+                    CertificateFactory cf = CertificateFactory.getInstance("X.509","BC");
+                    result = (X509CRL) cf.generateCRL(conn.getInputStream());
+                }
+                else
+                {
+                    throw new Exception(conn.getResponseMessage());
+                }
+            }
+        }
+        catch (Exception e)
+        {
+            ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+                    "CertPathReviewer.loadCrlDistPointError",
+                    new Object[] {new UntrustedInput(location),
+                                  e.getMessage(),e});
+            throw new CertPathReviewerException(msg);
+        }
+        return result;
+    }
+    
+    private Collection getTrustAnchors(X509Certificate cert, Set trustanchors) throws CertPathReviewerException
+    {
+        Collection trustColl = new ArrayList();
+        Iterator it = trustanchors.iterator();
+        
+        X509CertSelector certSelectX509 = new X509CertSelector();
+
+        try
+        {
+            certSelectX509.setSubject(getEncodedIssuerPrincipal(cert).getEncoded());
+        }
+        catch (IOException ex)
+        {
+            ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.trustAnchorIssuerError");
+            throw new CertPathReviewerException(msg);
+        }
+
+        while (it.hasNext())
+        {
+            TrustAnchor trust = (TrustAnchor) it.next();
+            if (trust.getTrustedCert() != null)
+            {
+                if (certSelectX509.match(trust.getTrustedCert()))
+                {
+                    trustColl.add(trust);
+                }
+            }
+            else if (trust.getCAName() != null && trust.getCAPublicKey() != null)
+            {
+                X500Principal certIssuer = getEncodedIssuerPrincipal(cert);
+                X500Principal caName = new X500Principal(trust.getCAName());
+                if (certIssuer.equals(caName))
+                {
+                    trustColl.add(trust);
+                }
+            }
+        }
+        return trustColl;
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/x509/X509Attribute.java b/libcore/security/src/main/java/org/bouncycastle/x509/X509Attribute.java
new file mode 100644
index 0000000..f4c65ab
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/x509/X509Attribute.java
@@ -0,0 +1,78 @@
+package org.bouncycastle.x509;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSet;
+import org.bouncycastle.asn1.x509.Attribute;
+
+/**
+ * Class for carrying the values in an X.509 Attribute.
+ */
+public class X509Attribute
+    extends ASN1Encodable
+{
+    Attribute    attr;
+    
+    /**
+     * @param at an object representing an attribute.
+     */
+    X509Attribute(
+        ASN1Encodable   at)
+    {
+        this.attr = Attribute.getInstance(at);
+    }
+
+    /**
+     * Create an X.509 Attribute with the type given by the passed in oid and
+     * the value represented by an ASN.1 Set containing value.
+     * 
+     * @param oid type of the attribute
+     * @param value value object to go into the atribute's value set.
+     */
+    public X509Attribute(
+        String          oid,
+        ASN1Encodable   value)
+    {
+        this.attr = new Attribute(new DERObjectIdentifier(oid), new DERSet(value));
+    }
+    
+    /**
+     * Create an X.59 Attribute with the type given by the passed in oid and the
+     * value represented by an ASN.1 Set containing the objects in value.
+     * 
+     * @param oid type of the attribute
+     * @param value vector of values to go in the attribute's value set.
+     */
+    public X509Attribute(
+        String              oid,
+        ASN1EncodableVector value)
+    {
+        this.attr = new Attribute(new DERObjectIdentifier(oid), new DERSet(value));
+    }
+    
+    public String getOID()
+    {
+        return attr.getAttrType().getId();
+    }
+    
+    public ASN1Encodable[] getValues()
+    {
+        ASN1Set         s = attr.getAttrValues();
+        ASN1Encodable[] values = new ASN1Encodable[s.size()];
+        
+        for (int i = 0; i != s.size(); i++)
+        {
+            values[i] = (ASN1Encodable)s.getObjectAt(i);
+        }
+        
+        return values;
+    }
+    
+    public DERObject toASN1Object()
+    {
+        return attr.toASN1Object();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/x509/X509AttributeCertificate.java b/libcore/security/src/main/java/org/bouncycastle/x509/X509AttributeCertificate.java
new file mode 100644
index 0000000..f3b0668
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/x509/X509AttributeCertificate.java
@@ -0,0 +1,106 @@
+package org.bouncycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509Extension;
+import java.util.Date;
+import java.util.Set;
+
+/**
+ * Interface for an X.509 Attribute Certificate.
+ */
+public interface X509AttributeCertificate
+    extends X509Extension
+{   
+    /**
+     * Return the version number for the certificate.
+     * 
+     * @return the version number.
+     */
+    public int getVersion();
+    
+    /**
+     * Return the serial number for the certificate.
+     * 
+     * @return the serial number.
+     */
+    public BigInteger getSerialNumber();
+    
+    /**
+     * Return the date before which the certificate is not valid.
+     * 
+     * @return the "not valid before" date.
+     */
+    public Date getNotBefore();
+    
+    /**
+     * Return the date after which the certificate is not valid.
+     * 
+     * @return the "not valid afer" date.
+     */
+    public Date getNotAfter();
+    
+    /**
+     * Return the holder of the certificate.
+     * 
+     * @return the holder.
+     */
+    public AttributeCertificateHolder getHolder();
+    
+    /**
+     * Return the issuer details for the certificate.
+     * 
+     * @return the issuer details.
+     */
+    public AttributeCertificateIssuer getIssuer();
+    
+    /**
+     * Return the attributes contained in the attribute block in the certificate.
+     * 
+     * @return an array of attributes.
+     */
+    public X509Attribute[] getAttributes();
+    
+    /**
+     * Return the attributes with the same type as the passed in oid.
+     * 
+     * @param oid the object identifier we wish to match.
+     * @return an array of matched attributes, null if there is no match.
+     */
+    public X509Attribute[] getAttributes(String oid);
+    
+    public boolean[] getIssuerUniqueID();
+    
+    public Set getNonCriticalExtensionOIDs();
+
+    public Set getCriticalExtensionOIDs();
+    
+    public void checkValidity()
+        throws CertificateExpiredException, CertificateNotYetValidException;
+    
+    public void checkValidity(Date date)
+        throws CertificateExpiredException, CertificateNotYetValidException;
+    
+    public byte[] getSignature();
+    
+    public void verify(PublicKey key, String provider)
+            throws CertificateException, NoSuchAlgorithmException,
+            InvalidKeyException, NoSuchProviderException, SignatureException;
+    
+    /**
+     * Return an ASN.1 encoded byte array representing the attribute certificate.
+     * 
+     * @return an ASN.1 encoded byte array.
+     * @throws IOException if the certificate cannot be encoded.
+     */
+    public byte[] getEncoded()
+        throws IOException;
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/x509/X509Util.java b/libcore/security/src/main/java/org/bouncycastle/x509/X509Util.java
new file mode 100644
index 0000000..854ec3a
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/x509/X509Util.java
@@ -0,0 +1,133 @@
+package org.bouncycastle.x509;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+// import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+// END android-removed
+import org.bouncycastle.jce.X509Principal;
+import org.bouncycastle.util.Strings;
+
+class X509Util
+{
+    private static Hashtable algorithms = new Hashtable();
+    private static Set       noParams = new HashSet();
+    
+    static
+    {   
+        algorithms.put("MD2WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
+        algorithms.put("MD2WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
+        algorithms.put("MD5WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
+        algorithms.put("MD5WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
+        algorithms.put("SHA1WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
+        algorithms.put("SHA1WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
+        algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+        algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+        algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+        algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+        algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+        algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+        algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+        algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+        algorithms.put("RIPEMD160WITHRSAENCRYPTION", new DERObjectIdentifier("1.3.36.3.3.1.2"));
+        algorithms.put("RIPEMD160WITHRSA", new DERObjectIdentifier("1.3.36.3.3.1.2"));
+        // BEGIN android-removed
+        // algorithms.put("SHA1WITHDSA", X9ObjectIdentifiers.id_dsa_with_sha1);
+        // algorithms.put("DSAWITHSHA1", X9ObjectIdentifiers.id_dsa_with_sha1);
+        // algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+        // algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
+        // algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+        // algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
+        // algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+        // algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+        // algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+        // algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+        // END android-removed
+        algorithms.put("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+        algorithms.put("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+        
+        //
+        // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field. 
+        // The parameters field SHALL be NULL for RSA based signature algorithms.
+        //
+        // BEGIN android-removed
+        // noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
+        // noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
+        // noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);
+        // noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);
+        // noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);
+        // noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);
+        // noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
+        // noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
+        // END android-removed
+    }
+     
+    static DERObjectIdentifier getAlgorithmOID(
+        String algorithmName)
+    {
+        algorithmName = Strings.toUpperCase(algorithmName);
+        
+        if (algorithms.containsKey(algorithmName))
+        {
+            return (DERObjectIdentifier)algorithms.get(algorithmName);
+        }
+        
+        return new DERObjectIdentifier(algorithmName);
+    }
+    
+    static AlgorithmIdentifier getSigAlgID(
+        DERObjectIdentifier sigOid)
+    {
+        if (noParams.contains(sigOid))
+        {
+            return new AlgorithmIdentifier(sigOid);
+        }
+        else
+        {
+            // BEGIN android-changed
+            return new AlgorithmIdentifier(sigOid, DERNull.THE_ONE);
+            // END android-changed
+        }
+    }
+    
+    static Iterator getAlgNames()
+    {
+        Enumeration e = algorithms.keys();
+        List        l = new ArrayList();
+        
+        while (e.hasMoreElements())
+        {
+            l.add(e.nextElement());
+        }
+        
+        return l.iterator();
+    }
+
+    static X509Principal convertPrincipal(
+        X500Principal principal)
+    {
+        try
+        {
+            return new X509Principal(principal.getEncoded());
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("cannot convert principal");
+        }
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java b/libcore/security/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java
new file mode 100644
index 0000000..09531b6
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java
@@ -0,0 +1,301 @@
+package org.bouncycastle.x509;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Iterator;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x509.TBSCertificateStructure;
+import org.bouncycastle.asn1.x509.Time;
+import org.bouncycastle.asn1.x509.V1TBSCertificateGenerator;
+import org.bouncycastle.asn1.x509.X509CertificateStructure;
+import org.bouncycastle.asn1.x509.X509Name;
+import org.bouncycastle.jce.X509Principal;
+import org.bouncycastle.jce.provider.X509CertificateObject;
+
+/**
+ * class to produce an X.509 Version 1 certificate.
+ */
+public class X509V1CertificateGenerator
+{
+    private V1TBSCertificateGenerator   tbsGen;
+    private DERObjectIdentifier         sigOID;
+    private AlgorithmIdentifier         sigAlgId;
+    private String                      signatureAlgorithm;
+
+    public X509V1CertificateGenerator()
+    {
+        tbsGen = new V1TBSCertificateGenerator();
+    }
+
+    /**
+     * reset the generator
+     */
+    public void reset()
+    {
+        tbsGen = new V1TBSCertificateGenerator();
+    }
+
+    /**
+     * set the serial number for the certificate.
+     */
+    public void setSerialNumber(
+        BigInteger      serialNumber)
+    {
+        if (serialNumber.compareTo(BigInteger.ZERO) <= 0)
+        {
+            throw new IllegalArgumentException("serial number must be a positive integer");
+        }
+        
+        tbsGen.setSerialNumber(new DERInteger(serialNumber));
+    }
+
+    /**
+     * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+     * certificate.
+     */
+    public void setIssuerDN(
+        X500Principal   issuer)
+    {
+        try
+        {
+            tbsGen.setIssuer(new X509Principal(issuer.getEncoded()));
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("can't process principal: " + e);
+        }
+    }
+    
+    /**
+     * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+     * certificate.
+     */
+    public void setIssuerDN(
+        X509Name   issuer)
+    {
+        tbsGen.setIssuer(issuer);
+    }
+
+    public void setNotBefore(
+        Date    date)
+    {
+        tbsGen.setStartDate(new Time(date));
+    }
+
+    public void setNotAfter(
+        Date    date)
+    {
+        tbsGen.setEndDate(new Time(date));
+    }
+
+    /**
+     * Set the subject distinguished name. The subject describes the entity associated with the public key.
+     */
+    public void setSubjectDN(
+        X500Principal   subject)
+    {
+        try
+        {
+            tbsGen.setSubject(new X509Principal(subject.getEncoded()));
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("can't process principal: " + e);
+        }
+    }
+    
+    /**
+     * Set the subject distinguished name. The subject describes the entity associated with the public key.
+     */
+    public void setSubjectDN(
+        X509Name   subject)
+    {
+        tbsGen.setSubject(subject);
+    }
+
+    public void setPublicKey(
+        PublicKey       key)
+    {
+        try
+        {
+            tbsGen.setSubjectPublicKeyInfo(new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream(
+                                new ByteArrayInputStream(key.getEncoded())).readObject()));
+        }
+        catch (Exception e)
+        {
+            throw new IllegalArgumentException("unable to process key - " + e.toString());
+        }
+    }
+
+    /**
+     * Set the signature algorithm. This can be either a name or an OID, names
+     * are treated as case insensitive.
+     * 
+     * @param signatureAlgorithm string representation of the algorithm name.
+     */
+    public void setSignatureAlgorithm(
+        String  signatureAlgorithm)
+    {
+        this.signatureAlgorithm = signatureAlgorithm;
+
+        try
+        {
+            sigOID = X509Util.getAlgorithmOID(signatureAlgorithm);
+        }
+        catch (Exception e)
+        {
+            throw new IllegalArgumentException("Unknown signature type requested");
+        }
+
+        sigAlgId = X509Util.getSigAlgID(sigOID);
+
+        tbsGen.setSignature(sigAlgId);
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject
+     * using the default provider "BC".
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key)
+        throws SecurityException, SignatureException, InvalidKeyException
+    {
+        try
+        {
+            return generateX509Certificate(key, "BC", null);
+        }
+        catch (NoSuchProviderException e)
+        {
+            throw new SecurityException("BC provider not installed!");
+        }
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject
+     * using the default provider "BC" and the passed in source of randomness
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key,
+        SecureRandom    random)
+        throws SecurityException, SignatureException, InvalidKeyException
+    {
+        try
+        {
+            return generateX509Certificate(key, "BC", random);
+        }
+        catch (NoSuchProviderException e)
+        {
+            throw new SecurityException("BC provider not installed!");
+        }
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject,
+     * using the passed in provider for the signing, and the passed in source
+     * of randomness (if required).
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key,
+        String          provider)
+        throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+    {
+        return generateX509Certificate(key, provider, null);
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject,
+     * using the passed in provider for the signing, and the passed in source
+     * of randomness (if required).
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key,
+        String          provider,
+        SecureRandom    random)
+        throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+    {
+        Signature sig = null;
+
+        try
+        {
+            sig = Signature.getInstance(sigOID.getId(), provider);
+        }
+        catch (NoSuchAlgorithmException ex)
+        {
+            try
+            {
+                sig = Signature.getInstance(signatureAlgorithm, provider);
+            }
+            catch (NoSuchAlgorithmException e)
+            {
+                throw new SecurityException("exception creating signature: " + e.toString());
+            }
+        }
+
+        if (random != null)
+        {
+            sig.initSign(key, random);
+        }
+        else
+        {
+            sig.initSign(key);
+        }
+
+        TBSCertificateStructure tbsCert = tbsGen.generateTBSCertificate();
+
+        try
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DEROutputStream         dOut = new DEROutputStream(bOut);
+
+            dOut.writeObject(tbsCert);
+
+            sig.update(bOut.toByteArray());
+        }
+        catch (Exception e)
+        {
+            throw new SecurityException("exception encoding TBS cert - " + e);
+        }
+
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(tbsCert);
+        v.add(sigAlgId);
+        v.add(new DERBitString(sig.sign()));
+
+        return new X509CertificateObject(new X509CertificateStructure(new DERSequence(v)));
+    }
+    
+    /**
+     * Return an iterator of the signature names supported by the generator.
+     * 
+     * @return an iterator containing recognised names.
+     */
+    public Iterator getSignatureAlgNames()
+    {
+        return X509Util.getAlgNames();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificate.java b/libcore/security/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificate.java
new file mode 100644
index 0000000..7348b87
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificate.java
@@ -0,0 +1,297 @@
+package org.bouncycastle.x509;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.asn1.x509.AttributeCertificate;
+import org.bouncycastle.asn1.x509.X509Extension;
+import org.bouncycastle.asn1.x509.X509Extensions;
+
+/*
+ * An implementation of a version 2 X.509 Attribute Certificate.
+ */
+public class X509V2AttributeCertificate
+    implements X509AttributeCertificate
+{
+    private AttributeCertificate    cert;
+    private Date                    notBefore;
+    private Date                    notAfter;
+    
+    public X509V2AttributeCertificate(
+        InputStream encIn)
+        throws IOException
+    {
+        this(AttributeCertificate.getInstance(new ASN1InputStream(encIn).readObject()));
+    }
+    
+    public X509V2AttributeCertificate(
+        byte[]  encoded)
+        throws IOException
+    {
+        this(new ByteArrayInputStream(encoded));
+    }
+    
+    X509V2AttributeCertificate(
+        AttributeCertificate    cert)
+        throws IOException
+    {
+        this.cert = cert;
+        
+        try
+        {
+            this.notAfter = cert.getAcinfo().getAttrCertValidityPeriod().getNotAfterTime().getDate();
+            this.notBefore = cert.getAcinfo().getAttrCertValidityPeriod().getNotBeforeTime().getDate();
+        }
+        catch (ParseException e)
+        {
+            throw new IOException("invalid data structure in certificate!");
+        }
+    }
+    
+    public int getVersion()
+    {
+        return cert.getAcinfo().getVersion().getValue().intValue();
+    }
+    
+    public BigInteger getSerialNumber()
+    {
+        return cert.getAcinfo().getSerialNumber().getValue();
+    }
+    
+    public AttributeCertificateHolder getHolder()
+    {
+        return new AttributeCertificateHolder((ASN1Sequence)cert.getAcinfo().getHolder().toASN1Object());
+    }
+    
+    public AttributeCertificateIssuer getIssuer()
+    {
+        return new AttributeCertificateIssuer(cert.getAcinfo().getIssuer());
+    }
+    
+    public Date getNotBefore()
+    {
+        return notBefore;
+    }
+    
+    public Date getNotAfter()
+    {
+        return notAfter;
+    }
+    
+    public boolean[] getIssuerUniqueID()
+    {
+        DERBitString    id = cert.getAcinfo().getIssuerUniqueID();
+
+        if (id != null)
+        {
+            byte[]          bytes = id.getBytes();
+            boolean[]       boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+            for (int i = 0; i != boolId.length; i++)
+            {
+                boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+            }
+
+            return boolId;
+        }
+            
+        return null;
+    }
+    
+    public void checkValidity() 
+        throws CertificateExpiredException, CertificateNotYetValidException
+    {
+        this.checkValidity(new Date());
+    }
+    
+    public void checkValidity(
+        Date    date)
+        throws CertificateExpiredException, CertificateNotYetValidException
+    {
+        if (date.after(this.getNotAfter()))
+        {
+            throw new CertificateExpiredException("certificate expired on " + this.getNotAfter());
+        }
+
+        if (date.before(this.getNotBefore()))
+        {
+            throw new CertificateNotYetValidException("certificate not valid till " + this.getNotBefore());
+        }
+    }
+    
+    public byte[] getSignature()
+    {
+        return cert.getSignatureValue().getBytes();
+    }
+    
+    public final void verify(
+            PublicKey   key,
+            String      provider)
+            throws CertificateException, NoSuchAlgorithmException,
+            InvalidKeyException, NoSuchProviderException, SignatureException
+    {
+        Signature   signature = null;
+
+        if (!cert.getSignatureAlgorithm().equals(cert.getAcinfo().getSignature()))
+        {
+            throw new CertificateException("Signature algorithm in certificate info not same as outer certificate");
+        }
+
+        signature = Signature.getInstance(cert.getSignatureAlgorithm().getObjectId().getId(), provider);
+
+        signature.initVerify(key);
+
+        try
+        {
+            signature.update(cert.getAcinfo().getEncoded());
+        }
+        catch (IOException e)
+        {
+            throw new SignatureException("Exception encoding certificate info object");
+        }
+
+        if (!signature.verify(this.getSignature()))
+        {
+            throw new InvalidKeyException("Public key presented not for certificate signature");
+        }
+    }
+    
+    public byte[] getEncoded()
+        throws IOException
+    {
+        return cert.getEncoded();
+    }
+
+    public byte[] getExtensionValue(String oid) 
+    {
+        X509Extensions  extensions = cert.getAcinfo().getExtensions();
+
+        if (extensions != null)
+        {
+            X509Extension   ext = extensions.getExtension(new DERObjectIdentifier(oid));
+
+            if (ext != null)
+            {
+                ByteArrayOutputStream    bOut = new ByteArrayOutputStream();
+                DEROutputStream            dOut = new DEROutputStream(bOut);
+                
+                try
+                {
+                    dOut.writeObject(ext.getValue());
+
+                    return bOut.toByteArray();
+                }
+                catch (Exception e)
+                {
+                    throw new RuntimeException("error encoding " + e.toString());
+                }
+            }
+        }
+
+        return null;
+    }
+
+    private Set getExtensionOIDs(
+        boolean critical) 
+    {
+        X509Extensions  extensions = cert.getAcinfo().getExtensions();
+
+        if (extensions != null)
+        {
+            Set             set = new HashSet();
+            Enumeration     e = extensions.oids();
+
+            while (e.hasMoreElements())
+            {
+                DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+                X509Extension       ext = extensions.getExtension(oid);
+
+                if (ext.isCritical() == critical)
+                {
+                    set.add(oid.getId());
+                }
+            }
+
+            return set;
+        }
+
+        return null;
+    }
+    
+    public Set getNonCriticalExtensionOIDs() 
+    {
+        return getExtensionOIDs(false);
+    }
+
+    public Set getCriticalExtensionOIDs() 
+    {
+        return getExtensionOIDs(true);
+    }
+    
+    public boolean hasUnsupportedCriticalExtension()
+    {
+        Set  extensions = getCriticalExtensionOIDs();
+
+        return extensions != null && !extensions.isEmpty();
+    }
+
+    public X509Attribute[] getAttributes()
+    {
+        ASN1Sequence    seq = cert.getAcinfo().getAttributes();
+        X509Attribute[] attrs = new X509Attribute[seq.size()];
+        
+        for (int i = 0; i != seq.size(); i++)
+        {
+            attrs[i] = new X509Attribute((ASN1Encodable)seq.getObjectAt(i));
+        }
+        
+        return attrs;
+    }
+    
+    public X509Attribute[] getAttributes(String oid)
+    {
+        ASN1Sequence    seq = cert.getAcinfo().getAttributes();
+        List            list = new ArrayList();
+        
+        for (int i = 0; i != seq.size(); i++)
+        {
+            X509Attribute attr = new X509Attribute((ASN1Encodable)seq.getObjectAt(i));
+            if (attr.getOID().equals(oid))
+            {
+                list.add(attr);
+            }
+        }
+        
+        if (list.size() == 0)
+        {
+            return null;
+        }
+        
+        return (X509Attribute[])list.toArray(new X509Attribute[list.size()]);
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificateGenerator.java b/libcore/security/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificateGenerator.java
new file mode 100644
index 0000000..ec1a0d7
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificateGenerator.java
@@ -0,0 +1,283 @@
+package org.bouncycastle.x509;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.util.Date;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERGeneralizedTime;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.AttCertIssuer;
+import org.bouncycastle.asn1.x509.Attribute;
+import org.bouncycastle.asn1.x509.AttributeCertificate;
+import org.bouncycastle.asn1.x509.V2AttributeCertificateInfoGenerator;
+import org.bouncycastle.asn1.x509.AttributeCertificateInfo;
+import org.bouncycastle.asn1.x509.X509Extension;
+import org.bouncycastle.asn1.x509.X509Extensions;
+
+/**
+ * class to produce an X.509 Version 2 AttributeCertificate.
+ */
+public class X509V2AttributeCertificateGenerator
+{
+    private V2AttributeCertificateInfoGenerator   acInfoGen;
+    private DERObjectIdentifier         sigOID;
+    private AlgorithmIdentifier         sigAlgId;
+    private String                      signatureAlgorithm;
+    private Hashtable                   extensions = null;
+    private Vector                      extOrdering = null;
+
+    public X509V2AttributeCertificateGenerator()
+    {
+        acInfoGen = new V2AttributeCertificateInfoGenerator();
+    }
+
+    /**
+     * reset the generator
+     */
+    public void reset()
+    {
+        acInfoGen = new V2AttributeCertificateInfoGenerator();
+        extensions = null;
+        extOrdering = null;
+    }
+
+    /**
+     * Set the Holder of this Attribute Certificate
+     */
+    public void setHolder(
+        AttributeCertificateHolder     holder)
+    {
+        acInfoGen.setHolder(holder.holder);
+    }
+
+    /**
+     * Set the issuer
+     */
+    public void setIssuer(
+        AttributeCertificateIssuer  issuer)
+    {
+        acInfoGen.setIssuer(AttCertIssuer.getInstance(issuer.form));
+    }
+
+    /**
+     * set the serial number for the certificate.
+     */
+    public void setSerialNumber(
+        BigInteger      serialNumber)
+    {
+        acInfoGen.setSerialNumber(new DERInteger(serialNumber));
+    }
+
+    public void setNotBefore(
+        Date    date)
+    {
+        acInfoGen.setStartDate(new DERGeneralizedTime(date));
+    }
+
+    public void setNotAfter(
+        Date    date)
+    {
+        acInfoGen.setEndDate(new DERGeneralizedTime(date));
+    }
+
+    /**
+     * Set the signature algorithm. This can be either a name or an OID, names
+     * are treated as case insensitive.
+     * 
+     * @param signatureAlgorithm string representation of the algorithm name.
+     */
+    public void setSignatureAlgorithm(
+        String  signatureAlgorithm)
+    {
+        this.signatureAlgorithm = signatureAlgorithm;
+
+        try
+        {
+            sigOID = X509Util.getAlgorithmOID(signatureAlgorithm);
+        }
+        catch (Exception e)
+        {
+            throw new IllegalArgumentException("Unknown signature type requested");
+        }
+
+        // BEGIN android-changed
+        sigAlgId = new AlgorithmIdentifier(this.sigOID, DERNull.THE_ONE);
+        // END android-changed
+
+        acInfoGen.setSignature(sigAlgId);
+    }
+    
+    /**
+     * add an attribute
+     */
+    public void addAttribute(
+        X509Attribute       attribute)
+    {
+        acInfoGen.addAttribute(Attribute.getInstance(attribute.toASN1Object()));
+    }
+
+    public void setIssuerUniqueId(
+        boolean[] iui)
+    {
+        // [TODO] convert boolean array to bit string
+        //acInfoGen.setIssuerUniqueID(iui);
+        throw new RuntimeException("not implemented (yet)");
+    }
+     
+    /**
+     * add a given extension field for the standard extensions tag
+     * @throws IOException
+     */
+    public void addExtension(
+        String          OID,
+        boolean         critical,
+        ASN1Encodable   value)
+        throws IOException
+    {
+        this.addExtension(OID, critical, value.getEncoded());
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag
+     * The value parameter becomes the contents of the octet string associated
+     * with the extension.
+     */
+    public void addExtension(
+        String          OID,
+        boolean         critical,
+        byte[]          value)
+    {
+        if (extensions == null)
+        {
+            extensions = new Hashtable();
+            extOrdering = new Vector();
+        }
+
+        DERObjectIdentifier oid = new DERObjectIdentifier(OID);
+        
+        extensions.put(oid, new X509Extension(critical, new DEROctetString(value)));
+        extOrdering.addElement(oid);
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject,
+     * using the passed in provider for the signing.
+     */
+    public X509AttributeCertificate generateCertificate(
+        PrivateKey      key,
+        String          provider)
+        throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+    {
+        return generateCertificate(key, provider, null);
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject,
+     * using the passed in provider for the signing and the supplied source
+     * of randomness, if required.
+     */
+    public X509AttributeCertificate generateCertificate(
+        PrivateKey      key,
+        String          provider,
+        SecureRandom    random)
+        throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+    {
+        Signature sig = null;
+
+        if (sigOID == null)
+        {
+            throw new IllegalStateException("no signature algorithm specified");
+        }
+
+        try
+        {
+            sig = Signature.getInstance(sigOID.getId(), provider);
+        }
+        catch (NoSuchAlgorithmException ex)
+        {
+            try
+            {
+                sig = Signature.getInstance(signatureAlgorithm, provider);
+            }
+            catch (NoSuchAlgorithmException e)
+            {
+                throw new SecurityException("exception creating signature: " + e.toString());
+            }
+        }
+
+        if (random != null)
+        {
+            sig.initSign(key, random);
+        }
+        else
+        {
+            sig.initSign(key);
+        }
+
+        if (extensions != null)
+        {
+            acInfoGen.setExtensions(new X509Extensions(extOrdering, extensions));
+        }
+
+        AttributeCertificateInfo acInfo = acInfoGen.generateAttributeCertificateInfo();
+
+        try
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DEROutputStream         dOut = new DEROutputStream(bOut);
+
+            dOut.writeObject(acInfo);
+
+            sig.update(bOut.toByteArray());
+        }
+        catch (Exception e)
+        {
+            throw new SecurityException("exception encoding Attribute cert - " + e);
+        }
+
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(acInfo);
+        v.add(sigAlgId);
+        v.add(new DERBitString(sig.sign()));
+
+        try
+        {
+            return new X509V2AttributeCertificate(new AttributeCertificate(new DERSequence(v)));
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException("constructed invalid certificate!");
+        }
+    }
+    
+    /**
+     * Return an iterator of the signature names supported by the generator.
+     * 
+     * @return an iterator containing recognised names.
+     */
+    public Iterator getSignatureAlgNames()
+    {
+        return X509Util.getAlgNames();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/x509/X509V2CRLGenerator.java b/libcore/security/src/main/java/org/bouncycastle/x509/X509V2CRLGenerator.java
new file mode 100644
index 0000000..f639be6
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/x509/X509V2CRLGenerator.java
@@ -0,0 +1,400 @@
+package org.bouncycastle.x509;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.SimpleTimeZone;
+import java.util.Vector;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DEREncodable;
+import org.bouncycastle.asn1.DERGeneralizedTime;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.CertificateList;
+import org.bouncycastle.asn1.x509.TBSCertList;
+import org.bouncycastle.asn1.x509.Time;
+import org.bouncycastle.asn1.x509.V2TBSCertListGenerator;
+import org.bouncycastle.asn1.x509.X509Extension;
+import org.bouncycastle.asn1.x509.X509Extensions;
+import org.bouncycastle.asn1.x509.X509Name;
+import org.bouncycastle.jce.X509Principal;
+import org.bouncycastle.jce.provider.X509CRLObject;
+
+/**
+ * class to produce an X.509 Version 2 CRL.
+ */
+public class X509V2CRLGenerator
+{
+    private SimpleDateFormat            dateF = new SimpleDateFormat("yyMMddHHmmss");
+    private SimpleTimeZone              tz = new SimpleTimeZone(0, "Z");
+    private V2TBSCertListGenerator      tbsGen;
+    private DERObjectIdentifier         sigOID;
+    private AlgorithmIdentifier         sigAlgId;
+    private String                      signatureAlgorithm;
+    private Hashtable                   extensions = null;
+    private Vector                      extOrdering = null;
+
+    public X509V2CRLGenerator()
+    {
+        dateF.setTimeZone(tz);
+
+        tbsGen = new V2TBSCertListGenerator();
+    }
+
+    /**
+     * reset the generator
+     */
+    public void reset()
+    {
+        tbsGen = new V2TBSCertListGenerator();
+    }
+
+    /**
+     * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+     * certificate.
+     */
+    public void setIssuerDN(
+        X500Principal   issuer)
+    {
+        try
+        {
+            tbsGen.setIssuer(new X509Principal(issuer.getEncoded()));
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("can't process principal: " + e);
+        }
+    }
+
+    /**
+     * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+     * certificate.
+     */
+    public void setIssuerDN(
+        X509Name   issuer)
+    {
+        tbsGen.setIssuer(issuer);
+    }
+
+    public void setThisUpdate(
+        Date    date)
+    {
+        tbsGen.setThisUpdate(new Time(date));
+    }
+
+    public void setNextUpdate(
+        Date    date)
+    {
+        tbsGen.setNextUpdate(new Time(date));
+    }
+
+    /**
+     * Reason being as indicated by ReasonFlags, i.e. ReasonFlags.keyCompromise
+     * or 0 if ReasonFlags are not to be used
+     **/
+    public void addCRLEntry(BigInteger userCertificate, Date revocationDate, int reason)
+    {
+        tbsGen.addCRLEntry(new DERInteger(userCertificate), new Time(revocationDate), reason);
+    }
+
+    /**
+     * Add a CRL entry with an Invalidity Date extension as well as a CRLReason extension.
+     * Reason being as indicated by ReasonFlags, i.e. ReasonFlags.keyCompromise
+     * or 0 if ReasonFlags are not to be used
+     **/
+    public void addCRLEntry(BigInteger userCertificate, Date revocationDate, int reason, Date invalidityDate)
+    {
+        tbsGen.addCRLEntry(new DERInteger(userCertificate), new Time(revocationDate), reason, new DERGeneralizedTime(invalidityDate));
+    }
+   
+    /**
+     * Add a CRL entry with extensions.
+     **/
+    public void addCRLEntry(BigInteger userCertificate, Date revocationDate, X509Extensions extensions)
+    {
+        tbsGen.addCRLEntry(new DERInteger(userCertificate), new Time(revocationDate), extensions);
+    }
+    
+    /**
+     * Add the CRLEntry objects contained in a previous CRL.
+     * 
+     * @param other the X509CRL to source the other entries from. 
+     */
+    public void addCRL(X509CRL other)
+        throws CRLException
+    {
+        Set revocations = other.getRevokedCertificates();
+        
+        Iterator it = revocations.iterator();
+        while (it.hasNext())
+        {
+            X509CRLEntry entry = (X509CRLEntry)it.next();
+            
+            ASN1InputStream aIn = new ASN1InputStream(entry.getEncoded());
+            
+            try
+            {
+                tbsGen.addCRLEntry(ASN1Sequence.getInstance(aIn.readObject()));
+            }
+            catch (IOException e)
+            {
+                throw new CRLException("exception processing encoding of CRL: " + e.toString());
+            }
+        }
+    }
+    
+    /**
+     * Set the signature algorithm. This can be either a name or an OID, names
+     * are treated as case insensitive.
+     * 
+     * @param signatureAlgorithm string representation of the algorithm name.
+     */
+    public void setSignatureAlgorithm(
+        String  signatureAlgorithm)
+    {
+        this.signatureAlgorithm = signatureAlgorithm;
+
+        try
+        {
+            sigOID = X509Util.getAlgorithmOID(signatureAlgorithm);
+        }
+        catch (Exception e)
+        {
+            throw new IllegalArgumentException("Unknown signature type requested");
+        }
+
+        sigAlgId = X509Util.getSigAlgID(sigOID);
+
+        tbsGen.setSignature(sigAlgId);
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag (tag 0)
+     */
+    public void addExtension(
+        String          OID,
+        boolean         critical,
+        DEREncodable    value)
+    {
+        this.addExtension(new DERObjectIdentifier(OID), critical, value);
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag (tag 0)
+     */
+    public void addExtension(
+        DERObjectIdentifier OID,
+        boolean             critical,
+        DEREncodable        value)
+    {
+        if (extensions == null)
+        {
+            extensions = new Hashtable();
+            extOrdering = new Vector();
+        }
+
+        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+        DEROutputStream         dOut = new DEROutputStream(bOut);
+
+        try
+        {
+            dOut.writeObject(value);
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("error encoding value: " + e);
+        }
+
+        this.addExtension(OID, critical, bOut.toByteArray());
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag (tag 0)
+     */
+    public void addExtension(
+        String          OID,
+        boolean         critical,
+        byte[]          value)
+    {
+        this.addExtension(new DERObjectIdentifier(OID), critical, value);
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag (tag 0)
+     */
+    public void addExtension(
+        DERObjectIdentifier OID,
+        boolean             critical,
+        byte[]              value)
+    {
+        if (extensions == null)
+        {
+            extensions = new Hashtable();
+            extOrdering = new Vector();
+        }
+
+        extensions.put(OID, new X509Extension(critical, new DEROctetString(value)));
+        extOrdering.addElement(OID);
+    }
+
+    /**
+     * generate an X509 CRL, based on the current issuer and subject
+     * using the default provider "BC".
+     */
+    public X509CRL generateX509CRL(
+        PrivateKey      key)
+        throws SecurityException, SignatureException, InvalidKeyException
+    {
+        try
+        {
+            return generateX509CRL(key, "BC", null);
+        }
+        catch (NoSuchProviderException e)
+        {
+            throw new SecurityException("BC provider not installed!");
+        }
+    }
+
+    /**
+     * generate an X509 CRL, based on the current issuer and subject
+     * using the default provider "BC" and an user defined SecureRandom object as
+     * source of randomness.
+     */
+    public X509CRL generateX509CRL(
+        PrivateKey      key,
+        SecureRandom    random)
+        throws SecurityException, SignatureException, InvalidKeyException
+    {
+        try
+        {
+            return generateX509CRL(key, "BC", random);
+        }
+        catch (NoSuchProviderException e)
+        {
+            throw new SecurityException("BC provider not installed!");
+        }
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject
+     * using the passed in provider for the signing.
+     */
+    public X509CRL generateX509CRL(
+        PrivateKey      key,
+        String          provider)
+        throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+    {
+        return generateX509CRL(key, provider, null);
+    }
+
+    /**
+     * generate an X509 CRL, based on the current issuer and subject,
+     * using the passed in provider for the signing.
+     */
+    public X509CRL generateX509CRL(
+        PrivateKey      key,
+        String          provider,
+        SecureRandom    random)
+        throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+    {
+        Signature sig = null;
+
+        try
+        {
+            sig = Signature.getInstance(sigOID.getId(), provider);
+        }
+        catch (NoSuchAlgorithmException ex)
+        {
+            try
+            {
+                sig = Signature.getInstance(signatureAlgorithm, provider);
+            }
+            catch (NoSuchAlgorithmException e)
+            {
+                throw new SecurityException("exception creating signature: " + e.toString());
+            }
+        }
+
+        if (random != null)
+        {
+            sig.initSign(key, random);
+        }
+        else
+        {
+            sig.initSign(key);
+        }
+
+        if (extensions != null)
+        {
+            tbsGen.setExtensions(new X509Extensions(extOrdering, extensions));
+        }
+
+        TBSCertList tbsCrl = tbsGen.generateTBSCertList();
+
+        try
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DEROutputStream         dOut = new DEROutputStream(bOut);
+
+            dOut.writeObject(tbsCrl);
+
+            sig.update(bOut.toByteArray());
+        }
+        catch (Exception e)
+        {
+            throw new SecurityException("exception encoding TBS cert - " + e);
+        }
+
+        // Construct the CRL
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(tbsCrl);
+        v.add(sigAlgId);
+        v.add(new DERBitString(sig.sign()));
+
+        try
+        {
+            return new X509CRLObject(new CertificateList(new DERSequence(v)));
+        }
+        catch (CRLException e)
+        {
+            throw new SecurityException("exception creating CRL: " + e.getMessage());
+        }
+    }
+    
+    
+    /**
+     * Return an iterator of the signature names supported by the generator.
+     * 
+     * @return an iterator containing recognised names.
+     */
+    public Iterator getSignatureAlgNames()
+    {
+        return X509Util.getAlgNames();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java b/libcore/security/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java
new file mode 100644
index 0000000..acfa0b4
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java
@@ -0,0 +1,429 @@
+package org.bouncycastle.x509;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.*;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x509.TBSCertificateStructure;
+import org.bouncycastle.asn1.x509.Time;
+import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
+import org.bouncycastle.asn1.x509.X509CertificateStructure;
+import org.bouncycastle.asn1.x509.X509Extension;
+import org.bouncycastle.asn1.x509.X509Extensions;
+import org.bouncycastle.asn1.x509.X509Name;
+import org.bouncycastle.jce.X509Principal;
+import org.bouncycastle.jce.provider.X509CertificateObject;
+import org.bouncycastle.x509.extension.X509ExtensionUtil;
+
+/**
+ * class to produce an X.509 Version 3 certificate.
+ */
+public class X509V3CertificateGenerator
+{
+    private V3TBSCertificateGenerator   tbsGen;
+    private DERObjectIdentifier         sigOID;
+    private AlgorithmIdentifier         sigAlgId;
+    private String                      signatureAlgorithm;
+    private Hashtable                   extensions = null;
+    private Vector                      extOrdering = null;
+
+    public X509V3CertificateGenerator()
+    {
+        tbsGen = new V3TBSCertificateGenerator();
+    }
+
+    /**
+     * reset the generator
+     */
+    public void reset()
+    {
+        tbsGen = new V3TBSCertificateGenerator();
+        extensions = null;
+        extOrdering = null;
+    }
+
+    /**
+     * set the serial number for the certificate.
+     */
+    public void setSerialNumber(
+        BigInteger      serialNumber)
+    {
+        if (serialNumber.compareTo(BigInteger.ZERO) <= 0)
+        {
+            throw new IllegalArgumentException("serial number must be a positive integer");
+        }
+        
+        tbsGen.setSerialNumber(new DERInteger(serialNumber));
+    }
+
+    /**
+     * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+     * certificate.
+     */
+    public void setIssuerDN(
+        X500Principal   issuer)
+    {
+        try
+        {
+            tbsGen.setIssuer(new X509Principal(issuer.getEncoded()));
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("can't process principal: " + e);
+        }
+    }
+    
+    /**
+     * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+     * certificate.
+     */
+    public void setIssuerDN(
+        X509Name   issuer)
+    {
+        tbsGen.setIssuer(issuer);
+    }
+
+    public void setNotBefore(
+        Date    date)
+    {
+        tbsGen.setStartDate(new Time(date));
+    }
+
+    public void setNotAfter(
+        Date    date)
+    {
+        tbsGen.setEndDate(new Time(date));
+    }
+
+    /**
+     * Set the subject distinguished name. The subject describes the entity associated with the public key.
+     */
+    public void setSubjectDN(
+        X500Principal   subject)
+    {
+        try
+        {
+            tbsGen.setSubject(new X509Principal(subject.getEncoded()));
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("can't process principal: " + e);
+        }
+    }
+    
+    /**
+     * Set the subject distinguished name. The subject describes the entity associated with the public key.
+     */
+    public void setSubjectDN(
+        X509Name   subject)
+    {
+        tbsGen.setSubject(subject);
+    }
+
+    public void setPublicKey(
+        PublicKey       key)
+    {
+        try
+        {
+            tbsGen.setSubjectPublicKeyInfo(new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream(
+                                new ByteArrayInputStream(key.getEncoded())).readObject()));
+        }
+        catch (Exception e)
+        {
+            throw new IllegalArgumentException("unable to process key - " + e.toString());
+        }
+    }
+
+    /**
+     * Set the signature algorithm. This can be either a name or an OID, names
+     * are treated as case insensitive.
+     * 
+     * @param signatureAlgorithm string representation of the algorithm name.
+     */
+    public void setSignatureAlgorithm(
+        String  signatureAlgorithm)
+    {
+        this.signatureAlgorithm = signatureAlgorithm;
+
+        try
+        {
+            sigOID = X509Util.getAlgorithmOID(signatureAlgorithm);
+        }
+        catch (Exception e)
+        {
+            throw new IllegalArgumentException("Unknown signature type requested: " + signatureAlgorithm);
+        }
+
+        sigAlgId = X509Util.getSigAlgID(sigOID);
+
+        tbsGen.setSignature(sigAlgId);
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag (tag 3)
+     */
+    public void addExtension(
+        String          oid,
+        boolean         critical,
+        DEREncodable    value)
+    {
+        this.addExtension(new DERObjectIdentifier(oid), critical, value);
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag (tag 3)
+     */
+    public void addExtension(
+        DERObjectIdentifier oid,
+        boolean             critical,
+        DEREncodable        value)
+    {
+        if (extensions == null)
+        {
+            extensions = new Hashtable();
+            extOrdering = new Vector();
+        }
+
+        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+        DEROutputStream         dOut = new DEROutputStream(bOut);
+
+        try
+        {
+            dOut.writeObject(value);
+        }
+        catch (IOException e)
+        {
+            throw new IllegalArgumentException("error encoding value: " + e);
+        }
+
+        this.addExtension(oid, critical, bOut.toByteArray());
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag (tag 3)
+     * The value parameter becomes the contents of the octet string associated
+     * with the extension.
+     */
+    public void addExtension(
+        String          oid,
+        boolean         critical,
+        byte[]          value)
+    {
+        this.addExtension(new DERObjectIdentifier(oid), critical, value);
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag (tag 3)
+     */
+    public void addExtension(
+        DERObjectIdentifier oid,
+        boolean             critical,
+        byte[]              value)
+    {
+        if (extensions == null)
+        {
+            extensions = new Hashtable();
+            extOrdering = new Vector();
+        }
+
+        extensions.put(oid, new X509Extension(critical, new DEROctetString(value)));
+        extOrdering.addElement(oid);
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag (tag 3)
+     * copying the extension value from another certificate.
+     * @throws CertificateParsingException if the extension cannot be extracted.
+     */
+    public void copyAndAddExtension(
+        String          oid,
+        boolean         critical,
+        X509Certificate cert) 
+        throws CertificateParsingException
+    {
+        byte[] extValue = cert.getExtensionValue(oid);
+        
+        if (extValue == null)
+        {
+            throw new CertificateParsingException("extension " + oid + " not present");
+        }
+        
+        try
+        {
+            ASN1Encodable value = X509ExtensionUtil.fromExtensionValue(extValue);
+    
+            this.addExtension(oid, critical, value);
+        }
+        catch (IOException e)
+        {
+            throw new CertificateParsingException(e.toString());
+        }
+    }
+
+    /**
+     * add a given extension field for the standard extensions tag (tag 3)
+     * copying the extension value from another certificate.
+     * @throws CertificateParsingException if the extension cannot be extracted.
+     */
+    public void copyAndAddExtension(
+        DERObjectIdentifier oid,
+        boolean             critical,
+        X509Certificate     cert)
+        throws CertificateParsingException
+    {
+        this.copyAndAddExtension(oid.getId(), critical, cert);
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject
+     * using the default provider "BC".
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key)
+        throws SecurityException, SignatureException, InvalidKeyException
+    {
+        try
+        {
+            return generateX509Certificate(key, "BC", null);
+        }
+        catch (NoSuchProviderException e)
+        {
+            throw new SecurityException("BC provider not installed!");
+        }
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject
+     * using the default provider "BC", and the passed in source of randomness
+     * (if required).
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key,
+        SecureRandom    random)
+        throws SecurityException, SignatureException, InvalidKeyException
+    {
+        try
+        {
+            return generateX509Certificate(key, "BC", random);
+        }
+        catch (NoSuchProviderException e)
+        {
+            throw new SecurityException("BC provider not installed!");
+        }
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject,
+     * using the passed in provider for the signing.
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key,
+        String          provider)
+        throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+    {
+        return generateX509Certificate(key, provider, null);
+    }
+
+    /**
+     * generate an X509 certificate, based on the current issuer and subject,
+     * using the passed in provider for the signing and the supplied source
+     * of randomness, if required.
+     */
+    public X509Certificate generateX509Certificate(
+        PrivateKey      key,
+        String          provider,
+        SecureRandom    random)
+        throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+    {
+        Signature sig = null;
+
+        if (sigOID == null)
+        {
+            throw new IllegalStateException("no signature algorithm specified");
+        }
+
+        try
+        {
+            sig = Signature.getInstance(sigOID.getId(), provider);
+        }
+        catch (NoSuchAlgorithmException ex)
+        {
+            try
+            {
+                sig = Signature.getInstance(signatureAlgorithm, provider);
+            }
+            catch (NoSuchAlgorithmException e)
+            {
+                throw new SecurityException("exception creating signature: " + e.toString());
+            }
+        }
+
+        if (random != null)
+        {
+            sig.initSign(key, random);
+        }
+        else
+        {
+            sig.initSign(key);
+        }
+
+        if (extensions != null)
+        {
+            tbsGen.setExtensions(new X509Extensions(extOrdering, extensions));
+        }
+
+        TBSCertificateStructure tbsCert = tbsGen.generateTBSCertificate();
+
+        try
+        {
+            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
+            DEROutputStream         dOut = new DEROutputStream(bOut);
+
+            dOut.writeObject(tbsCert);
+
+            sig.update(bOut.toByteArray());
+        }
+        catch (Exception e)
+        {
+            throw new SecurityException("exception encoding TBS cert - " + e);
+        }
+
+        ASN1EncodableVector  v = new ASN1EncodableVector();
+
+        v.add(tbsCert);
+        v.add(sigAlgId);
+        v.add(new DERBitString(sig.sign()));
+
+        return new X509CertificateObject(new X509CertificateStructure(new DERSequence(v)));
+    }
+    
+    /**
+     * Return an iterator of the signature names supported by the generator.
+     * 
+     * @return an iterator containing recognised names.
+     */
+    public Iterator getSignatureAlgNames()
+    {
+        return X509Util.getAlgNames();
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/x509/extension/AuthorityKeyIdentifierStructure.java b/libcore/security/src/main/java/org/bouncycastle/x509/extension/AuthorityKeyIdentifierStructure.java
new file mode 100644
index 0000000..2280198
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/x509/extension/AuthorityKeyIdentifierStructure.java
@@ -0,0 +1,126 @@
+package org.bouncycastle.x509.extension;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.PublicKey;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.GeneralNames;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x509.X509Extensions;
+import org.bouncycastle.jce.PrincipalUtil;
+
+/**
+ * A high level authority key identifier.
+ */
+public class AuthorityKeyIdentifierStructure
+    extends AuthorityKeyIdentifier
+{
+    /**
+     * Constructor which will take the byte[] returned from getExtensionValue()
+     * 
+     * @param encodedValue a DER octet encoded string with the extension structure in it.
+     * @throws IOException on parsing errors.
+     */
+    public AuthorityKeyIdentifierStructure(
+        byte[]  encodedValue)
+        throws IOException
+    {
+        super((ASN1Sequence)X509ExtensionUtil.fromExtensionValue(encodedValue));
+    }
+    
+    private static ASN1Sequence fromCertificate(
+        X509Certificate certificate)
+        throws CertificateParsingException
+    {
+        try
+        {
+            if (certificate.getVersion() != 3)
+            {
+                GeneralName          genName = new GeneralName(PrincipalUtil.getIssuerX509Principal(certificate));
+                SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+                        (ASN1Sequence)new ASN1InputStream(certificate.getPublicKey().getEncoded()).readObject());
+                
+                return (ASN1Sequence)new AuthorityKeyIdentifier(
+                               info, new GeneralNames(genName), certificate.getSerialNumber()).toASN1Object();
+            }
+            else
+            {
+                GeneralName             genName = new GeneralName(PrincipalUtil.getIssuerX509Principal(certificate));
+                
+                byte[]                  ext = certificate.getExtensionValue(X509Extensions.SubjectKeyIdentifier.getId());
+                
+                if (ext != null)
+                {
+                    ASN1OctetString     str = (ASN1OctetString)X509ExtensionUtil.fromExtensionValue(ext);
+                
+                    return (ASN1Sequence)new AuthorityKeyIdentifier(
+                                    str.getOctets(), new GeneralNames(genName), certificate.getSerialNumber()).toASN1Object();
+                }
+                else
+                {
+                    SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+                            (ASN1Sequence)new ASN1InputStream(certificate.getPublicKey().getEncoded()).readObject());
+                    
+                    return (ASN1Sequence)new AuthorityKeyIdentifier(
+                            info, new GeneralNames(genName), certificate.getSerialNumber()).toASN1Object();
+                }
+            }
+        }
+        catch (Exception e)
+        {
+            throw new CertificateParsingException("Exception extracting certificate details: " + e.toString());
+        }
+    }
+    
+    private static ASN1Sequence fromKey(
+        PublicKey pubKey)
+        throws InvalidKeyException
+    {
+        try
+        {
+            SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+                                        (ASN1Sequence)new ASN1InputStream(pubKey.getEncoded()).readObject());
+        
+            return (ASN1Sequence)new AuthorityKeyIdentifier(info).toASN1Object();
+        }
+        catch (Exception e)
+        {
+            throw new InvalidKeyException("can't process key: " + e);
+        }
+    }
+    
+    /**
+     * Create an AuthorityKeyIdentifier using the passed in certificate's public
+     * key, issuer and serial number.
+     * 
+     * @param certificate the certificate providing the information.
+     * @throws CertificateParsingException if there is a problem processing the certificate
+     */
+    public AuthorityKeyIdentifierStructure(
+        X509Certificate certificate)
+        throws CertificateParsingException
+    {
+        super(fromCertificate(certificate));
+    }
+    
+    /**
+     * Create an AuthorityKeyIdentifier using just the hash of the 
+     * public key.
+     * 
+     * @param pubKey the key to generate the hash from.
+     * @throws InvalidKeyException if there is a problem using the key.
+     */
+    public AuthorityKeyIdentifierStructure(
+        PublicKey pubKey) 
+        throws InvalidKeyException
+    {
+        super(fromKey(pubKey));
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/x509/extension/SubjectKeyIdentifierStructure.java b/libcore/security/src/main/java/org/bouncycastle/x509/extension/SubjectKeyIdentifierStructure.java
new file mode 100644
index 0000000..0b7ecd6
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/x509/extension/SubjectKeyIdentifierStructure.java
@@ -0,0 +1,58 @@
+package org.bouncycastle.x509.extension;
+
+import java.io.IOException;
+import java.security.PublicKey;
+import java.security.cert.CertificateParsingException;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+
+/**
+ * A high level subject key identifier.
+ */
+public class SubjectKeyIdentifierStructure
+    extends SubjectKeyIdentifier
+{
+    private AuthorityKeyIdentifier authKeyID;
+    
+    /**
+     * Constructor which will take the byte[] returned from getExtensionValue()
+     * 
+     * @param encodedValue a DER octet encoded string with the extension structure in it.
+     * @throws IOException on parsing errors.
+     */
+    public SubjectKeyIdentifierStructure(
+        byte[]  encodedValue)
+        throws IOException
+    {
+        super((ASN1OctetString)X509ExtensionUtil.fromExtensionValue(encodedValue));
+    }
+    
+    private static ASN1OctetString fromPublicKey(
+        PublicKey pubKey)
+        throws CertificateParsingException
+    {
+        try
+        {
+            SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+                (ASN1Sequence)new ASN1InputStream(pubKey.getEncoded()).readObject());
+
+            return (ASN1OctetString)(new SubjectKeyIdentifier(info).toASN1Object());
+        }
+        catch (Exception e)
+        {
+            throw new CertificateParsingException("Exception extracting certificate details: " + e.toString());
+        }
+    }
+    
+    public SubjectKeyIdentifierStructure(
+        PublicKey pubKey)
+        throws CertificateParsingException
+    {
+        super(fromPublicKey(pubKey));
+    }
+}
diff --git a/libcore/security/src/main/java/org/bouncycastle/x509/extension/X509ExtensionUtil.java b/libcore/security/src/main/java/org/bouncycastle/x509/extension/X509ExtensionUtil.java
new file mode 100644
index 0000000..22b1c12
--- /dev/null
+++ b/libcore/security/src/main/java/org/bouncycastle/x509/extension/X509ExtensionUtil.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.x509.extension;
+
+import java.io.IOException;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1OctetString;
+
+
+public class X509ExtensionUtil
+{
+    public static ASN1Encodable fromExtensionValue(
+        byte[]  encodedValue) 
+        throws IOException
+    {
+        ASN1InputStream aIn = new ASN1InputStream(encodedValue);
+        
+        aIn = new ASN1InputStream(((ASN1OctetString)aIn.readObject()).getOctets());
+        
+        return (ASN1Encodable)aIn.readObject();
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AccessControlException2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AccessControlException2Test.java
new file mode 100644
index 0000000..e9088de
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AccessControlException2Test.java
@@ -0,0 +1,82 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.io.FilePermission;
+import java.security.AccessControlException;
+
+public class AccessControlException2Test extends junit.framework.TestCase {
+    FilePermission filePermission;
+
+    AccessControlException acException;
+
+    AccessControlException acException1;
+
+    /**
+     * @tests java.security.AccessControlException#AccessControlException(java.lang.String)
+     */
+    public void test_ConstructorLjava_lang_String() {
+        // Test for method
+        // java.security.AccessControlException(java.lang.String)
+        assertTrue("AccessControlException's toString() should have returned "
+                + "'java.security.AccessControlException: test message' but "
+                + "returned: " + acException.toString(), acException.toString()
+                .equals("java.security.AccessControlException: test message"));
+    }
+
+    /**
+     * @tests java.security.AccessControlException#AccessControlException(java.lang.String,
+     *        java.security.Permission)
+     */
+    public void test_ConstructorLjava_lang_StringLjava_security_Permission() {
+        // Test for method
+        // java.security.AccessControlException(java.lang.String,
+        // java.security.Permission)
+        assertTrue("AccessControlException's toString() should have returned "
+                + "'java.security.AccessControlException: test message "
+                + "(java.io.FilePermission /* read)' but returned: "
+                + acException1.toString(), acException1.toString().equals(
+                "java.security.AccessControlException: test message"));
+    }
+
+    /**
+     * @tests java.security.AccessControlException#getPermission()
+     */
+    public void test_getPermission() {
+        // Test for method java.security.Permission
+        // java.security.AccessControlException.getPermission()
+        // make sure getPermission returns null when it's not set
+        assertNull(
+                "getPermission should have returned null if no permission was set",
+                acException.getPermission());
+        assertTrue(
+                "getPermission should have returned the permission we assigned to it",
+                acException1.getPermission() == filePermission);
+    }
+
+    /**
+     * Sets up the fixture, for example, open a network connection. This method
+     * is called before a test is executed.
+     */
+    protected void setUp() {
+        filePermission = new FilePermission("/*", "read");
+        acException = new AccessControlException("test message");
+        acException1 = new AccessControlException("test message",
+                filePermission);
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AccessControlExceptionTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AccessControlExceptionTest.java
new file mode 100644
index 0000000..cf58e97
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AccessControlExceptionTest.java
@@ -0,0 +1,72 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Astapchuk
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.AccessControlException;
+import java.security.AllPermission;
+import java.security.Permission;
+import java.security.UnresolvedPermission;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit test for AccessControlException.
+ */
+
+public class AccessControlExceptionTest extends TestCase {
+
+    /**
+     * Entry point for standalone run.
+     * @param args command line arguments
+     */
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(AccessControlExceptionTest.class);
+    }
+
+    /**
+     * Tests AccessControlException(String)
+     */
+    public void testAccessControlExceptionString() {
+        new AccessControlException(null);
+        new AccessControlException("Failure");
+    }
+
+    /**
+     * Tests AccessControlException(String, Permission)
+     */
+    public void testAccessControlExceptionStringPermission() {
+        Permission perm = new AllPermission();
+        new AccessControlException("001", perm);
+    }
+
+    /**
+     * 
+     * Tests AccessControlException.getPermission()
+     */
+    public void testGetPermission() {
+        Permission perm = new UnresolvedPermission("unresolvedType",
+                "unresolvedName", "unresolvedActions", null);
+        AccessControlException ex = new AccessControlException("001", perm);
+        assertSame(ex.getPermission(), perm);
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AccessController2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AccessController2Test.java
new file mode 100644
index 0000000..6ebb735
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AccessController2Test.java
@@ -0,0 +1,155 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.AccessController;
+import java.security.AllPermission;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+
+public class AccessController2Test extends junit.framework.TestCase {
+
+    /**
+     * @tests java.security.AccessController#doPrivileged(java.security.PrivilegedAction,
+     *        java.security.AccessControlContext))
+     */
+    public void testDoPrivilegedLjava_security_PrivilegedActionLjava_security_AccessControlContext() {
+        Boolean pass;
+
+        pass = (Boolean) AccessController.doPrivileged(
+                new PrivilegedAction<Boolean>() {
+                    public Boolean run() {
+                        try {
+                            AccessController
+                                    .checkPermission(new AllPermission());
+                            return new Boolean(false);
+                        } catch (SecurityException ex) {
+                            return new Boolean(true);
+                        }
+                    }
+                }, null);
+        assertTrue("Got AllPermission by passing in a null PD", pass
+                .booleanValue());
+
+        pass = (Boolean) AccessController.doPrivileged(
+                new PrivilegedAction<Boolean>() {
+                    public Boolean run() {
+                        try {
+                            AccessController
+                                    .checkPermission(new AllPermission());
+                            return new Boolean(false);
+                        } catch (SecurityException ex) {
+                            return new Boolean(true);
+                        }
+                    }
+                }, AccessController.getContext());
+        assertTrue("Got AllPermission by passing in not null PD", pass
+                .booleanValue());
+    }
+
+    /**
+     * @tests java.security.AccessController#doPrivileged(java.security.PrivilegedAction))
+     */
+    public void testDoPrivilegedLjava_security_PrivilegedAction() {
+        Boolean pass;
+
+        pass = (Boolean) AccessController
+                .doPrivileged(new PrivilegedAction<Boolean>() {
+                    public Boolean run() {
+                        try {
+                            AccessController
+                                    .checkPermission(new AllPermission());
+                            return new Boolean(false);
+                        } catch (SecurityException ex) {
+                            return new Boolean(true);
+                        }
+                    }
+                });
+        assertTrue("Got AllPermission by passing in a null PD", pass
+                .booleanValue());
+
+    }
+
+    /**
+     * @tests java.security.AccessController#doPrivileged(java.security.PrivilegedExceptionAction,
+     *        java.security.AccessControlContext))
+     */
+    public void testDoPrivilegedLjava_security_PrivilegedExceptionActionLjava_security_AccessControlContext() {
+        Boolean pass;
+        try {
+            pass = (Boolean) AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<Boolean>() {
+                        public Boolean run() {
+                            try {
+                                AccessController
+                                        .checkPermission(new AllPermission());
+                                return new Boolean(false);
+                            } catch (SecurityException ex) {
+                                return new Boolean(true);
+                            }
+                        }
+                    }, null);
+            assertTrue("Got AllPermission by passing in a null PD", pass
+                    .booleanValue());
+        } catch (PrivilegedActionException e) {
+            fail("Unexpected exception " + e.getMessage());
+        }
+
+        pass = (Boolean) AccessController.doPrivileged(
+                new PrivilegedAction<Boolean>() {
+                    public Boolean run() {
+                        try {
+                            AccessController
+                                    .checkPermission(new AllPermission());
+                            return new Boolean(false);
+                        } catch (SecurityException ex) {
+                            return new Boolean(true);
+                        }
+                    }
+                }, AccessController.getContext());
+        assertTrue("Got AllPermission by passing in not null PD", pass
+                .booleanValue());
+    }
+
+    /**
+     * @tests java.security.AccessController#doPrivileged(java.security.PrivilegedExceptionAction))
+     */
+    public void testDoPrivilegedLjava_security_PrivilegedExceptionAction() {
+        Boolean pass;
+        try {
+            pass = (Boolean) AccessController
+                    .doPrivileged(new PrivilegedExceptionAction<Boolean>() {
+                        public Boolean run() {
+                            try {
+                                AccessController
+                                        .checkPermission(new AllPermission());
+                                return new Boolean(false);
+                            } catch (SecurityException ex) {
+                                return new Boolean(true);
+                            }
+                        }
+                    });
+            assertTrue("Got AllPermission by passing in a null PD", pass
+                    .booleanValue());
+        } catch (PrivilegedActionException e) {
+            fail("Unexpected exception " + e.getMessage());
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AlgorithmParameterGenerator1Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AlgorithmParameterGenerator1Test.java
new file mode 100644
index 0000000..a07a52a
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AlgorithmParameterGenerator1Test.java
@@ -0,0 +1,396 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameterGeneratorSpi;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.apache.harmony.security.tests.support.MyAlgorithmParameterGeneratorSpi;
+import org.apache.harmony.security.tests.support.SpiEngUtils;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>AlgorithmParameterGenerator</code> class constructors and
+ * methods.
+ * 
+ */
+
+public class AlgorithmParameterGenerator1Test extends TestCase {
+    /**
+     * Constructor for AlgorithmParameterGeneratorTests.
+     * 
+     * @param arg0
+     */
+    public AlgorithmParameterGenerator1Test(String arg0) {
+        super(arg0);
+    }
+
+    private static String[] invalidValues = SpiEngUtils.invalidValues;
+    private static String validAlgName = "DSA";
+    private static String[] algs =  {
+            "DSA", "dsa", "Dsa", "DsA", "dsA" }; 
+            
+    public static final String srvAlgorithmParameterGenerator = "AlgorithmParameterGenerator";
+
+
+    private static String validProviderName = null;
+
+    private static Provider validProvider = null;
+
+    private static boolean DSASupported = false;
+
+    static {
+        validProvider = SpiEngUtils.isSupport(
+                validAlgName,
+                srvAlgorithmParameterGenerator);
+        DSASupported = (validProvider != null);
+        validProviderName = (DSASupported ? validProvider.getName() : null);
+    }
+
+    protected AlgorithmParameterGenerator[] createAPGen() {
+        if (!DSASupported) {
+            fail(validAlgName + " algorithm is not supported");
+            return null;
+        }
+        AlgorithmParameterGenerator[] apg = new AlgorithmParameterGenerator[3];
+        try {
+            apg[0] = AlgorithmParameterGenerator.getInstance(validAlgName);
+            apg[1] = AlgorithmParameterGenerator.getInstance(validAlgName,
+                    validProvider);
+            apg[2] = AlgorithmParameterGenerator.getInstance(validAlgName,
+                    validProviderName);
+            return apg;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * Test for <code>getInstance(String algorithm)</code> method
+     * Assertion: 
+     * throws NullPointerException must be thrown is null
+     * throws NoSuchAlgorithmException must be thrown if algorithm is not available
+     * 
+     */
+    public void testAlgorithmParameterGenerator01()
+            throws NoSuchAlgorithmException {
+        try {
+            AlgorithmParameterGenerator.getInstance(null);
+            fail("NullPointerException or NoSuchAlgorithmException should be thrown");
+        } catch (NullPointerException e) {
+        } catch (NoSuchAlgorithmException e) {
+        }
+        for (int i = 0; i < invalidValues.length; i++) {
+            try {
+                AlgorithmParameterGenerator.getInstance(invalidValues[i]);
+                fail("NoSuchAlgorithmException should be thrown");
+            } catch (NoSuchAlgorithmException e) {
+            }
+        }
+    }
+
+    /**
+     * Test for <code>getInstance(String algorithm)</code> method
+     * Assertion: returns AlgorithmParameterGenerator instance 
+     * when algorithm is DSA
+     */
+    public void testAlgorithmParameterGenerator02()
+            throws NoSuchAlgorithmException {
+        if (!DSASupported) {
+            fail(validAlgName + " algorithm is not supported");
+            return;
+        }
+        AlgorithmParameterGenerator apg;
+        for (int i = 0; i < algs.length; i++) {
+            apg = AlgorithmParameterGenerator.getInstance(algs[i]);
+            assertEquals("Incorrect algorithm", apg.getAlgorithm(), algs[i]);
+        }
+    }
+
+    /**
+     * Test for <code>getInstance(String algorithm, String provider)</code>
+     * method 
+     * Assertion: 
+     * throws IllegalArgumentException if provider is null or empty
+     */
+    public void testAlgorithmParameterGenerator03()
+            throws NoSuchAlgorithmException, NoSuchProviderException {
+        if (!DSASupported) {
+            fail(validAlgName + " algorithm is not supported");
+            return;
+        }
+        String provider = null;
+        for (int i = 0; i < algs.length; i++) {
+            try {
+                AlgorithmParameterGenerator.getInstance(algs[i], provider);
+                fail("IllegalArgumentException must be thrown when provider is null");
+            } catch (IllegalArgumentException e) {
+            }
+            try {
+                AlgorithmParameterGenerator.getInstance(algs[i], "");
+                fail("IllegalArgumentException must be thrown when provider is empty");
+            } catch (IllegalArgumentException e) {
+            }
+        }
+    }
+
+    /**
+     * Test for <code>getInstance(String algorithm, String provider)</code>
+     * method 
+     * Assertion: throws NoSuchProviderException if provider is not
+     * available
+     */
+    public void testAlgorithmParameterGenerator04()
+            throws NoSuchAlgorithmException {
+        if (!DSASupported) {
+            fail(validAlgName + " algorithm is not supported");
+            return;
+        }
+        for (int i = 0; i < algs.length; i++) {
+            for (int j = 1; j < invalidValues.length; j++) {
+                try {
+                    AlgorithmParameterGenerator.getInstance(algs[i],
+                            invalidValues[j]);
+                    fail("NoSuchProviderException must be thrown (provider: "
+                            .concat(invalidValues[j]));
+                } catch (NoSuchProviderException e) {
+                }
+            }
+        }
+    }
+
+    /**
+     * Test for <code>getInstance(String algorithm, String provider)</code>
+     * method 
+     * Assertion: 
+     * throws NullPointerException must be thrown is null
+     * throws NoSuchAlgorithmException must be thrown if algorithm is not available
+     */
+    public void testAlgorithmParameterGenerator05()
+            throws NoSuchProviderException {
+        if (!DSASupported) {
+            fail(validAlgName + " algorithm is not supported");
+            return;
+        }
+        try {
+            AlgorithmParameterGenerator.getInstance(null, validProviderName);
+            fail("NullPointerException or NoSuchAlgorithmException should be thrown");
+        } catch (NullPointerException e) {
+        } catch (NoSuchAlgorithmException e) {
+        }
+        for (int i = 0; i < invalidValues.length; i++) {
+            try {
+                AlgorithmParameterGenerator.getInstance(invalidValues[i],
+                        validProviderName);
+                fail("NoSuchAlgorithmException must be thrown when (algorithm: "
+                        .concat(invalidValues[i].concat(")")));
+            } catch (NoSuchAlgorithmException e) {
+            }
+        }
+    }
+
+    /**
+     * Test for <code>getInstance(String algorithm, String provider)</code>
+     * method 
+     * Assertion: return AlgorithmParameterGenerator
+     */
+    public void testAlgorithmParameterGenerator06()
+            throws NoSuchAlgorithmException, NoSuchProviderException {
+        if (!DSASupported) {
+            fail(validAlgName + " algorithm is not supported");
+            return;
+        }
+        AlgorithmParameterGenerator apg;
+        for (int i = 0; i < algs.length; i++) {
+            apg = AlgorithmParameterGenerator.getInstance(algs[i],
+                    validProviderName);
+            assertEquals("Incorrect algorithm", algs[i], apg.getAlgorithm());
+            assertEquals("Incorrect provider", apg.getProvider().getName(),
+                    validProviderName);
+        }
+    }
+
+    /**
+     * Test for <code>getInstance(String algorithm, Provider provider)</code>
+     * method 
+     * Assertion: throws IllegalArgumentException when provider is null
+     */
+    public void testAlgorithmParameterGenerator07()
+            throws NoSuchAlgorithmException {
+        if (!DSASupported) {
+            fail(validAlgName + " algorithm is not supported");
+            return;
+        }
+        Provider provider = null;
+        for (int i = 0; i < algs.length; i++) {
+            try {
+                AlgorithmParameterGenerator.getInstance(algs[i], provider);
+                fail("IllegalArgumentException must be thrown when provider is null");
+            } catch (IllegalArgumentException e) {
+            }
+        }
+    }
+
+    /**
+     * Test for <code>getInstance(String algorithm, Provider provider)</code>
+     * method 
+     * Assertion: 
+     * throws NullPointerException must be thrown is null
+     * throws NoSuchAlgorithmException must be thrown if algorithm is not available
+     */
+    public void testAlgorithmParameterGenerator08() {
+        if (!DSASupported) {
+            fail(validAlgName + " algorithm is not supported");
+            return;
+        }
+        try {
+            AlgorithmParameterGenerator.getInstance(null, validProvider);
+            fail("NullPointerException or NoSuchAlgorithmException should be thrown");
+        } catch (NullPointerException e) {
+        } catch (NoSuchAlgorithmException e) {
+        }
+        for (int i = 0; i < invalidValues.length; i++) {
+            try {
+                AlgorithmParameterGenerator.getInstance(invalidValues[i],
+                        validProvider);
+                fail("NoSuchAlgorithmException must be thrown (algorithm: "
+                        .concat(invalidValues[i]).concat(")"));
+            } catch (NoSuchAlgorithmException e) {
+            }
+        }
+    }
+
+    /**
+     * Test for <code>getInstance(String algorithm, Provider provider)</code>
+     * method 
+     * Assertion: returns AlgorithmParameterGenerator object
+     */
+    public void testAlgorithmParameterGenerator09()
+            throws NoSuchAlgorithmException {
+        if (!DSASupported) {
+            fail(validAlgName + " algorithm is not supported");
+            return;
+        }
+        AlgorithmParameterGenerator apg;
+        for (int i = 0; i < algs.length; i++) {
+            apg = AlgorithmParameterGenerator.getInstance(algs[i],
+                    validProvider);
+            assertEquals("Incorrect algorithm", apg.getAlgorithm(), algs[i]);
+            assertEquals("Incorrect provider", apg.getProvider(), validProvider);
+        }
+    }
+
+    /**
+     * Test for <code>generateParameters()</code> method
+     * Assertion: returns AlgorithmParameters object
+     */  
+    public void testAlgorithmParameterGenerator10()
+            throws NoSuchAlgorithmException {
+        if (!DSASupported) {
+            fail(validAlgName + " algorithm is not supported");
+            return;
+        }
+        AlgorithmParameterGenerator apg = AlgorithmParameterGenerator
+                .getInstance(validAlgName);
+        apg.init(512);
+        AlgorithmParameters ap = apg.generateParameters();
+        assertEquals("Incorrect algorithm", ap.getAlgorithm().toUpperCase(),
+                apg.getAlgorithm().toUpperCase());
+    }
+    
+    /**
+     * Test for <code>init(AlgorithmParameterSpec param)</code> and 
+     * <code>init(AlgorithmParameterSpec param, SecureRandom random<code> 
+     * methods
+     * Assertion: throws InvalidAlgorithmParameterException when param is null
+     */
+    public void testAlgorithmParameterGenerator12() {
+        if (!DSASupported) {
+            fail(validAlgName + " algorithm is not supported");
+            return;
+        }
+        SecureRandom random = new SecureRandom();
+        AlgorithmParameterSpec aps = null;
+        AlgorithmParameterGenerator[] apgs = createAPGen();
+        assertNotNull("AlgorithmParameterGenerator objects were not created",
+                apgs);
+        for (int i = 0; i < apgs.length; i++) {
+            try {
+                apgs[i].init(aps, random);
+                fail("InvalidAlgorithmParameterException must be throws when param is null");
+            } catch (InvalidAlgorithmParameterException e) {                    
+            }
+        }        
+    }
+    
+    /**
+     * Test for <code>AlgorithmParameterGenerator</code> constructor 
+     * Assertion: returns AlgorithmParameterGenerator object
+     */
+    public void testAlgorithmParameterGeneratorConstr() throws NoSuchAlgorithmException {
+        if (!DSASupported) {
+            fail(validAlgName + " algorithm is not supported");
+            return;
+        }
+        AlgorithmParameterGeneratorSpi spi = new MyAlgorithmParameterGeneratorSpi();
+        AlgorithmParameterGenerator apg = 
+                new myAlgPG(spi, validProvider, validAlgName);
+        assertEquals("Incorrect algorithm", apg.getAlgorithm(), validAlgName);
+        assertEquals("Incorrect provider",apg.getProvider(),validProvider);
+        try {
+            apg.init(-10, null);
+            fail("IllegalArgumentException must be thrown");
+        } catch (IllegalArgumentException e) {
+        }
+        
+        apg = new myAlgPG(null, null, null);
+        assertNull("Incorrect algorithm", apg.getAlgorithm());
+        assertNull("Incorrect provider", apg.getProvider());
+        try {
+            apg.init(-10, null);
+            fail("NullPointerException must be thrown");
+        } catch (NullPointerException e) {
+        }
+    }
+
+    public static void main(String args[]) {
+        junit.textui.TestRunner.run(AlgorithmParameterGenerator1Test.class);
+    }
+}
+/**
+ * Additional class to verify AlgorithmParameterGenerator constructor
+ */
+class myAlgPG extends AlgorithmParameterGenerator {
+    public myAlgPG(AlgorithmParameterGeneratorSpi spi, Provider prov, String alg) {
+        super(spi, prov, alg);
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AlgorithmParameterGenerator2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AlgorithmParameterGenerator2Test.java
new file mode 100644
index 0000000..7fc2171
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AlgorithmParameterGenerator2Test.java
@@ -0,0 +1,270 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.apache.harmony.security.tests.support.SpiEngUtils;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>AlgorithmParameterGenerator</code> class constructors and
+ * methods.
+ */
+
+public class AlgorithmParameterGenerator2Test extends TestCase {
+    
+    private static final String AlgorithmParameterGeneratorProviderClass = "org.apache.harmony.security.tests.support.MyAlgorithmParameterGeneratorSpi";
+
+    private static final String defaultAlg = "APG";
+
+    private static final String[] invalidValues = SpiEngUtils.invalidValues;
+
+    private static final String[] validValues;
+
+    static {
+        validValues = new String[4];
+        validValues[0] = defaultAlg;
+        validValues[1] = defaultAlg.toLowerCase();
+        validValues[2] = "apG";
+        validValues[3] = "ApG";
+    }
+
+    Provider mProv;
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        mProv = (new SpiEngUtils()).new MyProvider("MyAPGProvider", "Testing provider", 
+                AlgorithmParameterGenerator1Test.srvAlgorithmParameterGenerator.concat(".").concat(defaultAlg),
+                AlgorithmParameterGeneratorProviderClass);
+        Security.insertProviderAt(mProv, 1);
+    }
+    
+    /*
+     * @see TestCase#tearDown()
+     */
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        Security.removeProvider(mProv.getName());
+    }
+
+    /**
+     * Constructor for SecurityManagerFactoryTest2.
+     * 
+     * @param arg0
+     */
+    public AlgorithmParameterGenerator2Test(String arg0) {
+        super(arg0);
+    }
+
+    private void checkResult(AlgorithmParameterGenerator algParGen) 
+            throws InvalidAlgorithmParameterException {
+        AlgorithmParameters param = algParGen.generateParameters();
+        assertNull("Not null parameters", param);
+        
+        AlgorithmParameterSpec pp = null;
+        algParGen.init(pp, new SecureRandom());
+        algParGen.init(pp);
+        try {
+            algParGen.init(pp, null);
+            fail("IllegalArgumentException must be thrown");
+        } catch (IllegalArgumentException e) {
+        }
+        pp = new tmpAlgorithmParameterSpec("Proba");
+        algParGen.init(pp, new SecureRandom());
+        algParGen.init(pp);
+        
+        algParGen.init(0, null);
+        algParGen.init(0, new SecureRandom());        
+        
+        try {
+            algParGen.init(-10, null);
+            fail("IllegalArgumentException must be thrown");
+        } catch (IllegalArgumentException e) {
+        }
+        try {
+            algParGen.init(-10, new SecureRandom());
+            fail("IllegalArgumentException must be thrown");
+        } catch (IllegalArgumentException e) {
+        }
+    }
+    /**
+     * Test for <code>getInstance(String algorithm)</code> method
+     * Assertions:
+     * throws NullPointerException must be thrown is null
+     * throws NoSuchAlgorithmException must be thrown if algorithm is not available
+     * returns AlgorithmParameterGenerator object
+     */
+    public void testGetInstance01() throws NoSuchAlgorithmException,
+            InvalidAlgorithmParameterException {
+        try {
+            AlgorithmParameterGenerator.getInstance(null);
+            fail("NullPointerException or NoSuchAlgorithmException should be thrown");
+        } catch (NullPointerException e) {
+        } catch (NoSuchAlgorithmException e) {
+        }
+        for (int i = 0; i < invalidValues.length; i++) {
+            try {
+                AlgorithmParameterGenerator.getInstance(invalidValues[i]);
+                fail("NoSuchAlgorithmException must be thrown (algorithm: "
+                        .concat(invalidValues[i]).concat(")"));
+            } catch (NoSuchAlgorithmException e) {
+            }
+        }
+        AlgorithmParameterGenerator apG;
+        for (int i = 0; i < validValues.length; i++) {
+            apG = AlgorithmParameterGenerator.getInstance(validValues[i]);
+            assertEquals("Incorrect algorithm", apG.getAlgorithm(),
+                    validValues[i]);
+            assertEquals("Incorrect provider", apG.getProvider(), mProv);
+            checkResult(apG);
+        }
+    }
+
+    /**
+     * Test for <code>getInstance(String algorithm, String provider)</code>
+     * method
+     * Assertions: 
+     * throws NullPointerException must be thrown is null
+     * throws NoSuchAlgorithmException must be thrown if algorithm is not available
+     * throws IllegalArgumentException when provider is null;
+     * throws NoSuchProviderException when provider is available;
+     * returns AlgorithmParameterGenerator object
+     */
+    public void testGetInstance02() throws NoSuchAlgorithmException,
+            NoSuchProviderException, IllegalArgumentException,
+            InvalidAlgorithmParameterException {
+        try {
+            AlgorithmParameterGenerator.getInstance(null, mProv.getName());
+            fail("NullPointerException or NoSuchAlgorithmException should be thrown");
+        } catch (NullPointerException e) {
+        } catch (NoSuchAlgorithmException e) {
+        }
+        for (int i = 0; i < invalidValues.length; i++) {
+            try {
+                AlgorithmParameterGenerator.getInstance(invalidValues[i], mProv
+                        .getName());
+                fail("NoSuchAlgorithmException must be thrown (algorithm: "
+                        .concat(invalidValues[i]).concat(")"));
+            } catch (NoSuchAlgorithmException e) {
+            }
+        }
+        String prov = null;
+        for (int i = 0; i < validValues.length; i++) {
+            try {
+                AlgorithmParameterGenerator.getInstance(validValues[i], prov);
+                fail("IllegalArgumentException must be thrown when provider is null (algorithm: "
+                        .concat(invalidValues[i]).concat(")"));
+            } catch (IllegalArgumentException e) {
+            }
+        }
+        for (int i = 0; i < validValues.length; i++) {
+            for (int j = 1; j < invalidValues.length; j++) {
+                try {
+                    AlgorithmParameterGenerator.getInstance(validValues[i],
+                            invalidValues[j]);
+                    fail("NoSuchProviderException must be thrown (algorithm: "
+                            .concat(invalidValues[i]).concat(" provider: ")
+                            .concat(invalidValues[j]).concat(")"));
+                } catch (NoSuchProviderException e) {
+                }
+            }
+        }
+        AlgorithmParameterGenerator apG;
+        for (int i = 0; i < validValues.length; i++) {
+            apG = AlgorithmParameterGenerator.getInstance(validValues[i], mProv
+                    .getName());
+            assertEquals("Incorrect algorithm", apG.getAlgorithm(),
+                    validValues[i]);
+            assertEquals("Incorrect provider", apG.getProvider().getName(),
+                    mProv.getName());
+            checkResult(apG);
+        }
+    }
+
+    /**
+     * Test for <code>getInstance(String algorithm, Provider provider)</code>
+     * method
+     * Assertions:
+     * throws NullPointerException must be thrown is null
+     * throws NoSuchAlgorithmException must be thrown if algorithm is not available
+     * throws IllegalArgumentException when provider is null;
+     * returns AlgorithmParameterGenerator object
+     */
+    public void testGetInstance03() throws NoSuchAlgorithmException,
+            IllegalArgumentException,
+            InvalidAlgorithmParameterException {
+        try {
+            AlgorithmParameterGenerator.getInstance(null, mProv);
+            fail("NullPointerException or NoSuchAlgorithmException should be thrown");
+        } catch (NullPointerException e) {
+        } catch (NoSuchAlgorithmException e) {
+        }
+        for (int i = 0; i < invalidValues.length; i++) {
+            try {
+                AlgorithmParameterGenerator.getInstance(invalidValues[i], mProv);
+                fail("NoSuchAlgorithmException must be thrown (algorithm: "
+                        .concat(invalidValues[i]).concat(")"));
+            } catch (NoSuchAlgorithmException e) {
+            }
+        }
+        Provider prov = null;
+        for (int i = 0; i < validValues.length; i++) {
+            try {
+                AlgorithmParameterGenerator.getInstance(validValues[i], prov);
+                fail("IllegalArgumentException must be thrown when provider is null (algorithm: "
+                        .concat(invalidValues[i]).concat(")"));
+            } catch (IllegalArgumentException e) {
+            }
+        }
+        AlgorithmParameterGenerator apG;
+        for (int i = 0; i < validValues.length; i++) {
+            apG = AlgorithmParameterGenerator.getInstance(validValues[i], mProv);
+            assertEquals("Incorrect algorithm", apG.getAlgorithm(),
+                    validValues[i]);
+            assertEquals("Incorrect provider", apG.getProvider(), mProv);
+            checkResult(apG);
+        }
+    }
+    /**
+     * Additional class for init(...) methods verification
+     */
+    class tmpAlgorithmParameterSpec implements AlgorithmParameterSpec {
+        private final String type;
+        public tmpAlgorithmParameterSpec(String type) {
+            this.type = type;
+        }
+        public String getType() {
+            return type;
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AlgorithmParameterGenerator3Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AlgorithmParameterGenerator3Test.java
new file mode 100644
index 0000000..0b0ddcd
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AlgorithmParameterGenerator3Test.java
@@ -0,0 +1,192 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.math.BigInteger;
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.spec.DSAParameterSpec;
+
+public class AlgorithmParameterGenerator3Test extends junit.framework.TestCase {
+
+    /**
+     * @tests java.security.AlgorithmParameterGenerator#generateParameters()
+     */
+    public void test_generateParameters() throws Exception {
+
+        //fail("Takes ages. Problem with SecureRandom and stub math ?");
+        
+        // Test for method java.security.AlgorithmParameters
+        // java.security.AlgorithmParameterGenerator.generateParameters()
+        AlgorithmParameterGenerator gen = AlgorithmParameterGenerator
+                .getInstance("DSA");
+        gen.init(1024);
+
+        // WARNING - The next line can take MINUTES to run
+        AlgorithmParameters params = gen.generateParameters();
+        assertNotNull("params is null", params);
+    }
+
+    /**
+     * @tests java.security.AlgorithmParameterGenerator#getAlgorithm()
+     */
+    public void test_getAlgorithm() throws Exception {
+        // Test for method java.lang.String
+        // java.security.AlgorithmParameterGenerator.getAlgorithm()
+        String alg = AlgorithmParameterGenerator.getInstance("DSA")
+                .getAlgorithm();
+        assertEquals("getAlgorithm ok", "DSA", alg);
+    }
+
+    /**
+     * @tests java.security.AlgorithmParameterGenerator#getInstance(java.lang.String)
+     */
+    public void test_getInstanceLjava_lang_String() throws Exception {
+        // Test for method java.security.AlgorithmParameterGenerator
+        // java.security.AlgorithmParameterGenerator.getInstance(java.lang.String)
+        AlgorithmParameterGenerator.getInstance("DSA");
+    }
+
+    /**
+     * @tests java.security.AlgorithmParameterGenerator#getInstance(java.lang.String,
+     *        java.lang.String)
+     */
+    public void test_getInstanceLjava_lang_StringLjava_lang_String() throws Exception {
+        // Test for method java.security.AlgorithmParameterGenerator
+        // java.security.AlgorithmParameterGenerator.getInstance(java.lang.String,
+        // java.lang.String)
+
+        // Opting for DSA here as it is pretty widely supported
+               Provider[] provs = Security
+                       .getProviders("AlgorithmParameterGenerator.DSA");
+
+        for (int i = 0; i < provs.length; i++) {
+                AlgorithmParameterGenerator.getInstance("DSA", provs[i].getName());
+            }// end for
+
+
+        // exception case - should throw IllegalArgumentException for null
+        // provider
+        try {
+            AlgorithmParameterGenerator.getInstance("DSA", (String) null);
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // Expected
+        }
+
+        // exception case - should throw IllegalArgumentException for empty
+        // provider
+        try {
+            AlgorithmParameterGenerator.getInstance("DSA", "");
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // Expected
+        }
+
+        // exception case - should throw NoSuchProviderException
+        try {
+            AlgorithmParameterGenerator.getInstance("DSA", "IDontExist");
+            fail("Should have thrown NoSuchProviderException");
+        } catch (NoSuchProviderException e) {
+            // Expected
+        }
+    }
+
+    /**
+     * @tests java.security.AlgorithmParameterGenerator#getProvider()
+     */
+    public void test_getProvider() throws Exception {
+        // Test for method java.security.Provider
+        // java.security.AlgorithmParameterGenerator.getProvider()
+            // checks that no exception is thrown
+        Provider p = AlgorithmParameterGenerator.getInstance("DSA")
+                .getProvider();
+        assertNotNull("provider is null", p);
+    }
+
+    /**
+     * @tests java.security.AlgorithmParameterGenerator#init(int)
+     */
+    public void test_initI() throws Exception {
+        // Test for method void
+        // java.security.AlgorithmParameterGenerator.init(int)
+            // checks that no exception is thrown
+        AlgorithmParameterGenerator gen = AlgorithmParameterGenerator
+                .getInstance("DSA");
+        gen.init(1024);
+    }
+
+    /**
+     * @tests java.security.AlgorithmParameterGenerator#init(int,
+     *        java.security.SecureRandom)
+     */
+    public void test_initILjava_security_SecureRandom() throws Exception {
+        // Test for method void
+        // java.security.AlgorithmParameterGenerator.init(int,
+        // java.security.SecureRandom)
+            // checks that no exception is thrown
+        AlgorithmParameterGenerator gen = AlgorithmParameterGenerator
+                .getInstance("DSA");
+        gen.init(1024, new SecureRandom());
+    }
+
+    /**
+     * @tests java.security.AlgorithmParameterGenerator#init(java.security.spec.AlgorithmParameterSpec)
+     */
+    public void test_initLjava_security_spec_AlgorithmParameterSpec() throws Exception {
+        // Test for method void
+        // java.security.AlgorithmParameterGenerator.init(java.security.spec.AlgorithmParameterSpec)
+        // checks that InvalidAlgorithmParameterException is thrown
+        DSAParameterSpec spec = new DSAParameterSpec(BigInteger.ONE,
+                BigInteger.ONE, BigInteger.ONE);
+        AlgorithmParameterGenerator gen = AlgorithmParameterGenerator
+                .getInstance("DSA");
+        try {
+            gen.init(spec);
+            fail("No expected InvalidAlgorithmParameterException");
+        } catch (InvalidAlgorithmParameterException e) {
+            //expected
+        }
+    }
+
+    /**
+     * @tests java.security.AlgorithmParameterGenerator#init(java.security.spec.AlgorithmParameterSpec,
+     *        java.security.SecureRandom)
+     */
+    public void test_initLjava_security_spec_AlgorithmParameterSpecLjava_security_SecureRandom() throws Exception {
+        // Test for method void
+        // java.security.AlgorithmParameterGenerator.init(java.security.spec.AlgorithmParameterSpec,
+        // java.security.SecureRandom)
+        // checks that InvalidAlgorithmParameterException  is thrown
+        DSAParameterSpec spec = new DSAParameterSpec(BigInteger.ONE,
+                BigInteger.ONE, BigInteger.ONE);
+        AlgorithmParameterGenerator gen = AlgorithmParameterGenerator
+                .getInstance("DSA");
+        try {
+            gen.init(spec, new SecureRandom());
+            fail("No expected InvalidAlgorithmParameterException");
+        } catch (InvalidAlgorithmParameterException e) {
+            //expected
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AlgorithmParametersTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AlgorithmParametersTest.java
new file mode 100644
index 0000000..70a9f45
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AlgorithmParametersTest.java
@@ -0,0 +1,650 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris V. Kuznetsov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.AlgorithmParameters;
+import java.security.AlgorithmParametersSpi;
+import java.security.Provider;
+import java.security.Security;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>AlgorithmParameters</code> class constructors and
+ * methods.
+ * 
+ */
+public class AlgorithmParametersTest extends TestCase {
+
+    /**
+     * Provider
+     */
+    Provider p;
+    
+    /*
+     * @see TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+        super.setUp();
+        p = new MyProvider();
+        Security.insertProviderAt(p, 1);
+    }
+
+    /*
+     * @see TestCase#tearDown()
+     */
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        Security.removeProvider(p.getName());
+    }
+
+    /**
+     * @tests java.security.AlgorithmParameters#getAlgorithm()
+     */
+    public void test_getAlgorithm() throws Exception {
+
+        // test: null value
+        AlgorithmParameters ap = new DummyAlgorithmParameters(null, p, null);
+        assertNull(ap.getAlgorithm());
+
+        // test: not null value
+        ap = new DummyAlgorithmParameters(null, p, "AAA");
+        assertEquals("AAA", ap.getAlgorithm());
+    }
+
+    /**
+     * @tests java.security.AlgorithmParameters#getEncoded()
+     */
+    public void test_getEncoded() throws Exception {
+
+        final byte[] enc = new byte[] { 0x02, 0x01, 0x03 };
+
+        MyAlgorithmParameters paramSpi = new MyAlgorithmParameters() {
+            protected byte[] engineGetEncoded() throws IOException {
+                return enc;
+            }
+        };
+
+        AlgorithmParameters params = new DummyAlgorithmParameters(paramSpi, p,
+                "algorithm");
+
+        //
+        // test: IOException if not initialized
+        //
+        try {
+            params.getEncoded();
+            fail("should not get encoded from un-initialized instance");
+        } catch (IOException e) {
+            // expected
+        }
+
+        //
+        // test: corresponding spi method is invoked
+        //
+        params.init(new MyAlgorithmParameterSpec());
+        assertSame(enc, params.getEncoded());
+    }
+
+    /**
+     * @tests java.security.AlgorithmParameters#getEncoded(String)
+     */
+    public void test_getEncodedLjava_lang_String() throws Exception {
+
+        final byte[] enc = new byte[] { 0x02, 0x01, 0x03 };
+
+        final String strFormatParam = "format";
+
+        MyAlgorithmParameters paramSpi = new MyAlgorithmParameters() {
+            protected byte[] engineGetEncoded(String format) throws IOException {
+                assertEquals(strFormatParam, format);
+                return enc;
+            }
+        };
+
+        AlgorithmParameters params = new DummyAlgorithmParameters(paramSpi, p,
+                "algorithm");
+
+        //
+        // test: IOException if not initialized
+        //
+        try {
+            params.getEncoded(strFormatParam);
+            fail("should not get encoded from un-initialized instance");
+        } catch (IOException e) {
+            // expected
+        }
+
+        //
+        // test: corresponding spi method is invoked
+        //
+        params.init(new MyAlgorithmParameterSpec());
+        assertSame(enc, params.getEncoded(strFormatParam));
+        
+        //
+        // test: if format param is null
+        // Regression test for HARMONY-2680
+        //
+        paramSpi = new MyAlgorithmParameters() {
+            protected byte[] engineGetEncoded(String format) throws IOException {
+                assertNull(format); // null is passed to spi-provider
+                return enc;
+            }
+        };
+
+        params = new DummyAlgorithmParameters(paramSpi, p, "algorithm");
+        params.init(new MyAlgorithmParameterSpec());
+        assertSame(enc, params.getEncoded(null));
+    }
+
+    /**
+     * @tests java.security.AlgorithmParameters#getInstance(String)
+     */
+    public void test_getInstanceLjava_lang_String() throws Exception {
+
+        AlgorithmParameters ap = AlgorithmParameters.getInstance("ABC");
+
+        checkUnititialized(ap);
+
+        ap.init(new MyAlgorithmParameterSpec());
+
+        checkAP(ap, p);
+    }
+
+    /**
+     * @tests java.security.AlgorithmParameters#getInstance(String, String)
+     */
+    public void test_getInstanceLjava_lang_StringLjava_lang_String()
+            throws Exception {
+
+        AlgorithmParameters ap = AlgorithmParameters.getInstance("ABC",
+                "MyProvider");
+
+        checkUnititialized(ap);
+
+        ap.init(new byte[6]);
+
+        checkAP(ap, p);
+    }
+
+    /**
+     * @tests java.security.AlgorithmParameters#getParameterSpec(Class)
+     */
+    public void test_getParameterSpecLjava_lang_Class() throws Exception {
+
+        final MyAlgorithmParameterSpec myParamSpec = new MyAlgorithmParameterSpec();
+
+        MyAlgorithmParameters paramSpi = new MyAlgorithmParameters() {
+            protected AlgorithmParameterSpec engineGetParameterSpec(
+                    Class paramSpec) {
+                return myParamSpec;
+            }
+        };
+
+        AlgorithmParameters params = new DummyAlgorithmParameters(paramSpi, p,
+                "algorithm");
+
+        //
+        // test: InvalidParameterSpecException if not initialized
+        //
+        try {
+            params.getParameterSpec(null);
+            fail("No expected InvalidParameterSpecException");
+        } catch (InvalidParameterSpecException e) {
+            // expected
+        }
+        try {
+            params.getParameterSpec(MyAlgorithmParameterSpec.class);
+            fail("No expected InvalidParameterSpecException");
+        } catch (InvalidParameterSpecException e) {
+            // expected
+        }
+
+        //
+        // test: corresponding spi method is invoked
+        //
+        params.init(new MyAlgorithmParameterSpec());
+        assertSame(myParamSpec, params
+                .getParameterSpec(MyAlgorithmParameterSpec.class));
+
+        //
+        // test: if paramSpec is null
+        // Regression test for HARMONY-2733
+        //
+        paramSpi = new MyAlgorithmParameters() {
+
+            protected AlgorithmParameterSpec engineGetParameterSpec(
+                    Class paramSpec) {
+                assertNull(paramSpec); // null is passed to spi-provider
+                return null;
+            }
+        };
+
+        params = new DummyAlgorithmParameters(paramSpi, p, "algorithm");
+        params.init(new MyAlgorithmParameterSpec());
+        assertNull(params.getParameterSpec(null));
+    }
+
+    /**
+     * @tests java.security.AlgorithmParameters#getInstance(String, Provider)
+     */
+    public void test_getInstanceLjava_lang_StringLjava_security_Provider()
+            throws Exception {
+
+        AlgorithmParameters ap = AlgorithmParameters.getInstance("ABC", p);
+
+        checkUnititialized(ap);
+
+        ap.init(new byte[6], "aaa");
+
+        checkAP(ap, p);
+    }
+
+    /**
+     * @tests java.security.AlgorithmParameters#getProvider()
+     */
+    public void test_getProvider() throws Exception {
+        // test: null value
+        AlgorithmParameters ap = new DummyAlgorithmParameters(null, null, "AAA");
+        assertNull(ap.getProvider());
+
+        // test: not null value
+        ap = new DummyAlgorithmParameters(null, p, "AAA");
+        assertSame(p, ap.getProvider());
+    }
+
+    /**
+     * @tests java.security.AlgorithmParameters#init(java.security.spec.AlgorithmParameterSpec)
+     */
+    public void test_initLjava_security_spec_AlgorithmParameterSpec()
+            throws Exception {
+
+        //
+        // test: corresponding spi method is invoked
+        //
+        final MyAlgorithmParameterSpec spec = new MyAlgorithmParameterSpec();
+
+        MyAlgorithmParameters paramSpi = new MyAlgorithmParameters() {
+            protected void engineInit(AlgorithmParameterSpec paramSpec)
+                    throws InvalidParameterSpecException {
+                assertSame(spec, paramSpec);
+                runEngineInit_AlgParamSpec = true;
+            }
+        };
+
+        AlgorithmParameters params = new DummyAlgorithmParameters(paramSpi, p,
+                "algorithm");
+
+        params.init(spec);
+        assertTrue(paramSpi.runEngineInit_AlgParamSpec);
+
+        //
+        // test: InvalidParameterSpecException if already initialized
+        //
+        try {
+            params.init(spec);
+            fail("No expected InvalidParameterSpecException");
+        } catch (InvalidParameterSpecException e) {
+            // expected
+        }
+
+        params = new DummyAlgorithmParameters(paramSpi, p, "algorithm");
+        params.init(new byte[0]);
+        try {
+            params.init(spec);
+            fail("No expected InvalidParameterSpecException");
+        } catch (InvalidParameterSpecException e) {
+            // expected
+        }
+
+        params = new DummyAlgorithmParameters(paramSpi, p, "algorithm");
+        params.init(new byte[0], "format");
+        try {
+            params.init(spec);
+            fail("No expected InvalidParameterSpecException");
+        } catch (InvalidParameterSpecException e) {
+            // expected
+        }
+
+        //
+        // test: if paramSpec is null
+        //
+        paramSpi = new MyAlgorithmParameters() {
+
+            protected void engineInit(AlgorithmParameterSpec paramSpec)
+                    throws InvalidParameterSpecException {
+                assertNull(paramSpec);// null is passed to spi-provider
+                runEngineInit_AlgParamSpec = true;
+            }
+        };
+
+        params = new DummyAlgorithmParameters(paramSpi, p, "algorithm");
+        params.init((AlgorithmParameterSpec) null);
+        assertTrue(paramSpi.runEngineInit_AlgParamSpec);
+    }
+
+    /**
+     * @tests java.security.AlgorithmParameters#init(byte[])
+     */
+    public void test_init$B() throws Exception {
+
+        //
+        // test: corresponding spi method is invoked
+        //
+        final byte[] enc = new byte[] { 0x02, 0x01, 0x03 };
+
+        MyAlgorithmParameters paramSpi = new MyAlgorithmParameters() {
+            protected void engineInit(byte[] params) throws IOException {
+                runEngineInitB$ = true;
+                assertSame(enc, params);
+            }
+        };
+
+        AlgorithmParameters params = new DummyAlgorithmParameters(paramSpi, p,
+                "algorithm");
+
+        params.init(enc);
+        assertTrue(paramSpi.runEngineInitB$);
+
+        //
+        // test: IOException if already initialized
+        //
+        try {
+            params.init(enc);
+            fail("No expected IOException");
+        } catch (IOException e) {
+            // expected
+        }
+
+        params = new DummyAlgorithmParameters(paramSpi, p, "algorithm");
+        params.init(new MyAlgorithmParameterSpec());
+        try {
+            params.init(enc);
+            fail("No expected IOException");
+        } catch (IOException e) {
+            // expected
+        }
+
+        params = new DummyAlgorithmParameters(paramSpi, p, "algorithm");
+        params.init(enc, "format");
+        try {
+            params.init(enc);
+            fail("No expected IOException");
+        } catch (IOException e) {
+            // expected
+        }
+
+        //
+        // test: if params is null
+        //
+        paramSpi = new MyAlgorithmParameters() {
+
+            protected void engineInit(byte[] params) throws IOException {
+                runEngineInitB$ = true;
+                assertNull(params); // null is passed to spi-provider
+            }
+        };
+
+        params = new DummyAlgorithmParameters(paramSpi, p, "algorithm");
+        params.init((byte[]) null);
+        assertTrue(paramSpi.runEngineInitB$);
+    }
+
+    /**
+     * @tests java.security.AlgorithmParameters#init(byte[],String)
+     */
+    public void test_init$BLjava_lang_String() throws Exception {
+
+        //
+        // test: corresponding spi method is invoked
+        //
+        final byte[] enc = new byte[] { 0x02, 0x01, 0x03 };
+        final String strFormatParam = "format";
+
+        MyAlgorithmParameters paramSpi = new MyAlgorithmParameters() {
+            protected void engineInit(byte[] params, String format)
+                    throws IOException {
+
+                runEngineInitB$String = true;
+                assertSame(enc, params);
+                assertSame(strFormatParam, format);
+            }
+        };
+
+        AlgorithmParameters params = new DummyAlgorithmParameters(paramSpi, p,
+                "algorithm");
+
+        params.init(enc, strFormatParam);
+        assertTrue(paramSpi.runEngineInitB$String);
+
+        //
+        // test: IOException if already initialized
+        //
+        try {
+            params.init(enc, strFormatParam);
+            fail("No expected IOException");
+        } catch (IOException e) {
+            // expected
+        }
+
+        params = new DummyAlgorithmParameters(paramSpi, p, "algorithm");
+        params.init(new MyAlgorithmParameterSpec());
+        try {
+            params.init(enc, strFormatParam);
+            fail("No expected IOException");
+        } catch (IOException e) {
+            // expected
+        }
+
+        params = new DummyAlgorithmParameters(paramSpi, p, "algorithm");
+        params.init(enc);
+        try {
+            params.init(enc, strFormatParam);
+            fail("No expected IOException");
+        } catch (IOException e) {
+            // expected
+        }
+
+        //
+        // test: if params and format are null
+        // Regression test for HARMONY-2724
+        //
+        paramSpi = new MyAlgorithmParameters() {
+
+            protected void engineInit(byte[] params, String format)
+                    throws IOException {
+
+                runEngineInitB$String = true;
+
+                // null is passed to spi-provider
+                assertNull(params);
+                assertNull(format);
+            }
+        };
+
+        params = new DummyAlgorithmParameters(paramSpi, p, "algorithm");
+        params.init(null, null);
+        assertTrue(paramSpi.runEngineInitB$String);
+    }
+
+    /**
+     * @tests java.security.AlgorithmParameters#toString()
+     */
+    public void test_toString() throws Exception {
+
+        final String str = "AlgorithmParameters";
+
+        MyAlgorithmParameters paramSpi = new MyAlgorithmParameters() {
+            protected String engineToString() {
+                return str;
+            }
+        };
+
+        AlgorithmParameters params = new DummyAlgorithmParameters(paramSpi, p,
+                "algorithm");
+
+        assertNull("unititialized", params.toString());
+
+        params.init(new byte[0]);
+
+        assertSame(str, params.toString());
+    }
+
+    /**
+     * Tests DSA AlgorithmParameters provider
+     */
+    public void testDSAProvider() throws Exception {
+        AlgorithmParameters params = AlgorithmParameters.getInstance("DSA");
+
+        assertEquals("Algorithm", "DSA", params.getAlgorithm());
+
+        // init(AlgorithmParameterSpec)
+        BigInteger p = BigInteger.ONE;
+        BigInteger q = BigInteger.TEN;
+        BigInteger g = BigInteger.ZERO;
+        params.init(new DSAParameterSpec(p, q, g));
+
+        // getEncoded() and getEncoded(String) (TODO verify returned encoding)
+        byte[] enc = params.getEncoded();
+        assertNotNull(enc);
+        assertNotNull(params.getEncoded("ASN.1"));
+        // TODO assertNotNull(params.getEncoded(null)); // HARMONY-2680
+
+        // getParameterSpec(Class)
+        DSAParameterSpec spec = params.getParameterSpec(DSAParameterSpec.class);
+        assertEquals("p is wrong ", p, spec.getP());
+        assertEquals("q is wrong ", q, spec.getQ());
+        assertEquals("g is wrong ", g, spec.getG());
+
+        // init(byte[])
+        params = AlgorithmParameters.getInstance("DSA");
+        params.init(enc);
+        assertTrue("param encoded is different", Arrays.equals(enc, params
+                .getEncoded()));
+
+        // init(byte[], String)
+        params = AlgorithmParameters.getInstance("DSA");
+        params.init(enc, "ASN.1");
+        assertTrue("param encoded is different", Arrays.equals(enc, params
+                .getEncoded()));
+
+        params = AlgorithmParameters.getInstance("DSA");
+        try {
+            params.init(enc, "DOUGLASMAWSON");
+            params.init(enc, "DOUGLASMAWSON");
+            fail("IOException exception expected");
+        } catch (IOException e) {
+            // expected
+        }
+    }
+
+    /**
+     * Tests OAEP AlgorithmParameters provider
+     */
+    public void testOAEPProvider() throws Exception {
+        AlgorithmParameters params = AlgorithmParameters.getInstance("OAEP");
+
+        assertEquals("Algorithm", "OAEP", params.getAlgorithm());
+    }
+    
+    private void checkUnititialized(AlgorithmParameters ap) {
+        assertNull("Uninitialized: toString() failed", ap.toString());
+    }
+    
+    private void checkAP(AlgorithmParameters ap, Provider p) throws Exception {
+
+        assertSame("getProvider() failed", p, ap.getProvider());
+        assertEquals("getAlgorithm() failed", "ABC", ap.getAlgorithm());
+
+        assertEquals("AlgorithmParameters", ap.toString());
+        assertTrue("toString() failed", MyAlgorithmParameters.runEngineToString);
+    }
+
+    @SuppressWarnings("serial")
+    private class MyProvider extends Provider {
+        MyProvider() {
+            super("MyProvider", 1.0, "Provider for testing");
+            put("AlgorithmParameters.ABC", MyAlgorithmParameters.class
+                    .getName());
+        }
+
+        MyProvider(String name, double version, String info) {
+            super(name, version, info);
+        }
+    }
+    
+    private class MyAlgorithmParameterSpec implements java.security.spec.AlgorithmParameterSpec{
+    }
+    
+    private class DummyAlgorithmParameters extends AlgorithmParameters {
+        public DummyAlgorithmParameters(AlgorithmParametersSpi paramSpi, 
+                Provider provider, String algorithm) {
+            super(paramSpi, provider, algorithm);
+        }
+    }
+    
+    public static class MyAlgorithmParameters extends AlgorithmParametersSpi {
+
+        public boolean runEngineInit_AlgParamSpec = false;
+
+        public boolean runEngineInitB$ = false;
+
+        public boolean runEngineInitB$String = false;
+
+        public static boolean runEngineToString = false;
+
+        protected void engineInit(AlgorithmParameterSpec paramSpec)
+                throws InvalidParameterSpecException {
+        }
+
+        protected void engineInit(byte[] params) throws IOException {
+        }
+
+        protected void engineInit(byte[] params, String format)
+                throws IOException {
+        }
+
+        protected AlgorithmParameterSpec engineGetParameterSpec(Class paramSpec)
+                throws InvalidParameterSpecException {
+            return null;
+        }
+
+        protected byte[] engineGetEncoded() throws IOException {
+            return null;
+        }
+
+        protected byte[] engineGetEncoded(String format) throws IOException {
+            return null;
+        }
+
+        protected String engineToString() {
+            runEngineToString = true;
+            return "AlgorithmParameters";
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AllPermission2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AllPermission2Test.java
new file mode 100644
index 0000000..e651221
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AllPermission2Test.java
@@ -0,0 +1,145 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.AllPermission;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.SecurityPermission;
+import java.util.Enumeration;
+
+public class AllPermission2Test extends junit.framework.TestCase {
+
+    /**
+     * @tests java.security.AllPermission#AllPermission()
+     */
+    public void test_Constructor() {
+        // Test for method java.security.AllPermission()
+        AllPermission ap = new AllPermission();
+        assertEquals("Bogus name for AllPermission \"" + ap.getName() + "\".",
+                "<all permissions>", ap.getName());
+    }
+
+    /**
+     * @tests java.security.AllPermission#AllPermission(java.lang.String,
+     *        java.lang.String)
+     */
+    public void test_ConstructorLjava_lang_StringLjava_lang_String() {
+        // Test for method java.security.AllPermission(java.lang.String,
+        // java.lang.String)
+        AllPermission ap = new AllPermission("Don't remember this stupid name",
+                "or this action");
+        assertEquals("Bogus name for AllPermission \"" + ap.getName() + "\".",
+                "<all permissions>", ap.getName());
+        assertEquals(
+                "AllPermission constructed with actions didn't ignore them.",
+                "<all actions>", ap.getActions());
+    }
+
+    /**
+     * @tests java.security.AllPermission#equals(java.lang.Object)
+     */
+    public void test_equalsLjava_lang_Object() {
+        // Test for method boolean
+        // java.security.AllPermission.equals(java.lang.Object)
+        assertTrue("Two AllPermissions not equal to each other.",
+                new AllPermission().equals(new AllPermission()));
+        assertTrue("AllPermission equals a SecurityPermission.",
+                !(new AllPermission().equals(new SecurityPermission("ugh!"))));
+    }
+
+    /**
+     * @tests java.security.AllPermission#getActions()
+     */
+    public void test_getActions() {
+        AllPermission ap = new AllPermission();
+        // Test for method java.lang.String
+        // java.security.AllPermission.getActions()
+        assertTrue("AllPermission has non-empty actions. (" + ap.getActions()
+                + ")", ap.getActions().equals("<all actions>"));
+    }
+
+    /**
+     * @tests java.security.AllPermission#hashCode()
+     */
+    public void test_hashCode() {
+        final int ALLPERMISSION_HASH = 1;
+        // Test for method int java.security.AllPermission.hashCode()
+        AllPermission TestAllPermission = new AllPermission();
+        assertTrue("AllPermission hashCode is wrong. Should have been "
+                + ALLPERMISSION_HASH + " but was "
+                + TestAllPermission.hashCode(),
+                TestAllPermission.hashCode() == ALLPERMISSION_HASH);
+    }
+
+    /**
+     * @tests java.security.AllPermission#implies(java.security.Permission)
+     */
+    public void test_impliesLjava_security_Permission() {
+        // Test for method boolean
+        // java.security.AllPermission.implies(java.security.Permission)
+        assertTrue("AllPermission does not imply a AllPermission.",
+                new AllPermission().implies(new AllPermission()));
+        assertTrue("AllPermission does not imply a SecurityPermission.",
+                new AllPermission().implies(new SecurityPermission("ugh!")));
+        assertTrue("SecurityPermission implies AllPermission.",
+                !(new SecurityPermission("ugh!").implies(new AllPermission())));
+    }
+    
+    /**
+     * @tests java.security.AllPermission#newPermissionCollection()
+     */
+    public void test_newPermissionCollection() {
+        AllPermission ap1 = new AllPermission();
+        AllPermission ap2 = new AllPermission("Don't remember this stupid name",
+        "or this action");
+        AllPermission ap3 = new AllPermission("Remember this cool name",
+        "and this action");
+        
+        PermissionCollection pc1 = ap1.newPermissionCollection();
+        assertFalse(pc1.isReadOnly());
+        
+        Enumeration<Permission> perm1 = pc1.elements();
+        assertFalse(perm1.hasMoreElements());
+        assertNotNull(perm1);
+        
+        pc1.add(ap1);
+        pc1.add(ap2);
+        assertTrue("Should imply", pc1.implies(ap1));
+        assertTrue("Should imply", pc1.implies(ap2));
+        assertTrue("Should imply", pc1.implies(ap3));
+        perm1 = pc1.elements();
+        assertTrue(perm1.hasMoreElements());
+        
+        PermissionCollection pc2 = ap2.newPermissionCollection();
+        assertFalse(pc2.isReadOnly());
+        
+        Enumeration<Permission> perm2 = pc2.elements();
+        assertFalse(perm2.hasMoreElements());
+        assertNotNull(perm2);
+        
+        pc2.add(ap1);
+        pc2.add(ap2);
+        assertTrue("Should imply", pc2.implies(ap1));
+        assertTrue("Should imply", pc2.implies(ap2));
+        assertTrue("Should imply", pc2.implies(ap3));
+        perm2 = pc2.elements();
+        assertTrue(perm2.hasMoreElements());
+    }
+
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AllTests.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AllTests.java
new file mode 100644
index 0000000..10fb18a
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AllTests.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * This is autogenerated source file. Includes tests for package org.apache.harmony.security.tests.java.security;
+ */
+
+public class AllTests {
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(AllTests.suite());
+    }
+
+    public static Test suite() {
+        TestSuite suite = new TestSuite("All tests for package org.apache.harmony.security.tests.java.security;");
+        // $JUnit-BEGIN$
+
+        suite.addTestSuite(AccessControlException2Test.class);
+        suite.addTestSuite(AccessControlExceptionTest.class);
+        suite.addTestSuite(AccessController2Test.class);
+        suite.addTestSuite(AlgorithmParameterGenerator1Test.class);
+        suite.addTestSuite(AlgorithmParameterGenerator2Test.class);
+        suite.addTestSuite(AlgorithmParameterGenerator3Test.class);
+        suite.addTestSuite(AlgorithmParametersTest.class);
+        suite.addTestSuite(AllPermission2Test.class);
+        suite.addTestSuite(AuthProviderTest.class);
+        suite.addTestSuite(BasicPermission2Test.class);
+        suite.addTestSuite(CodeSignerTest.class);
+        suite.addTestSuite(CodeSource2Test.class);
+        suite.addTestSuite(CodeSourceTest.class);
+        suite.addTestSuite(DigestException2Test.class);
+        suite.addTestSuite(DigestExceptionTest.class);
+        suite.addTestSuite(DigestInputStream2Test.class);
+        suite.addTestSuite(DigestInputStreamTest.class);
+        suite.addTestSuite(DigestOutputStreamTest.class);
+        suite.addTestSuite(GeneralSecurityException2Test.class);
+        suite.addTestSuite(GeneralSecurityExceptionTest.class);
+        suite.addTestSuite(GuardedObjectTest.class);
+        suite.addTestSuite(Identity2Test.class);
+        suite.addTestSuite(IdentityScope2Test.class);
+        suite.addTestSuite(IdentityScopeTest.class);
+        suite.addTestSuite(InvalidAlgorithmParameterException2Test.class);
+        suite.addTestSuite(InvalidAlgorithmParameterExceptionTest.class);
+        suite.addTestSuite(InvalidKeyException2Test.class);
+        suite.addTestSuite(InvalidKeyExceptionTest.class);
+        suite.addTestSuite(InvalidParameterException2Test.class);
+        suite.addTestSuite(InvalidParameterExceptionTest.class);
+        suite.addTestSuite(KSCallbackHandlerProtectionTest.class);
+        suite.addTestSuite(KSPasswordProtectionTest.class);
+        suite.addTestSuite(KSPrivateKeyEntryTest.class);
+        suite.addTestSuite(KSSecretKeyEntryTest.class);
+        suite.addTestSuite(KSTrustedCertificateEntryTest.class);
+        suite.addTestSuite(KeyException2Test.class);
+        suite.addTestSuite(KeyExceptionTest.class);
+        suite.addTestSuite(KeyFactory2Test.class);
+        suite.addTestSuite(KeyManagementException2Test.class);
+        suite.addTestSuite(KeyManagementExceptionTest.class);
+        suite.addTestSuite(KeyPairGenerator1Test.class);
+        suite.addTestSuite(KeyPairGenerator2Test.class);
+        suite.addTestSuite(KeyPairGenerator3Test.class);
+        suite.addTestSuite(KeyPairGenerator4Test.class);
+        suite.addTestSuite(KeyPairGeneratorSpiTest.class);
+        suite.addTestSuite(KeyPairTest.class);
+        suite.addTestSuite(KeyRepTest.class);
+        suite.addTestSuite(KeyRepTypeTest.class);
+        suite.addTestSuite(KeyStore2Test.class);
+        suite.addTestSuite(KeyStore3Test.class);
+        suite.addTestSuite(KeyStoreBuilderTest.class);
+        suite.addTestSuite(KeyStoreException2Test.class);
+        suite.addTestSuite(KeyStoreExceptionTest.class);
+        suite.addTestSuite(KeyStoreSpiTest.class);
+        suite.addTestSuite(KeyStoreTest.class);
+        suite.addTestSuite(KeyTest.class);
+        suite.addTestSuite(MessageDigest1Test.class);
+        suite.addTestSuite(MessageDigest2Test.class);
+        suite.addTestSuite(MessageDigestSpiTest.class);
+        suite.addTestSuite(NoSuchAlgorithmException2Test.class);
+        suite.addTestSuite(NoSuchAlgorithmExceptionTest.class);
+        suite.addTestSuite(NoSuchProviderException2Test.class);
+        suite.addTestSuite(NoSuchProviderExceptionTest.class);
+        suite.addTestSuite(Permission2Test.class);
+        suite.addTestSuite(PermissionCollectionTest.class);
+        suite.addTestSuite(PermissionTest.class);
+        suite.addTestSuite(Permissions2Test.class);
+        suite.addTestSuite(PermissionsTest.class);
+        suite.addTestSuite(PolicyTest.class);
+        suite.addTestSuite(PrivateKeyTest.class);
+        suite.addTestSuite(PrivilegedActionException2Test.class);
+        suite.addTestSuite(PrivilegedActionExceptionTest.class);
+        suite.addTestSuite(ProtectionDomainTest.class);
+        suite.addTestSuite(Provider2Test.class);
+        suite.addTestSuite(ProviderException2Test.class);
+        suite.addTestSuite(ProviderExceptionTest.class);
+        suite.addTestSuite(ProviderServiceTest.class);
+        suite.addTestSuite(ProviderTest.class);
+        suite.addTestSuite(PublicKeyTest.class);
+        suite.addTestSuite(SecureClassLoader2Test.class);
+        suite.addTestSuite(SecureRandom2Test.class);
+        suite.addTestSuite(Security2Test.class);
+        suite.addTestSuite(SecurityPermission2Test.class);
+        suite.addTestSuite(SecurityPermissionTest.class);
+        suite.addTestSuite(SecurityTest.class);
+        suite.addTestSuite(Signature2Test.class);
+        suite.addTestSuite(SignatureException2Test.class);
+        suite.addTestSuite(SignatureExceptionTest.class);
+        suite.addTestSuite(SignatureSpiTest.class);
+        suite.addTestSuite(SignatureTest.class);
+        suite.addTestSuite(SignedObjectTest.class);
+        suite.addTestSuite(SignerTest.class);
+        suite.addTestSuite(TimestampTest.class);
+        suite.addTestSuite(UnrecoverableEntryExceptionTest.class);
+        suite.addTestSuite(UnrecoverableKeyException2Test.class);
+        suite.addTestSuite(UnrecoverableKeyExceptionTest.class);
+        suite.addTestSuite(UnresolvedPermissionTest.class);
+
+        // $JUnit-END$
+        return suite;
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AuthProviderTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AuthProviderTest.java
new file mode 100644
index 0000000..7e511b3
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/AuthProviderTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.AuthProvider;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+
+import junit.framework.TestCase;
+
+public class AuthProviderTest extends TestCase {
+
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    /**
+     * @tests java.security.AuthProvider#AuthProvider(String, double, String)
+     */
+    
+    public void testConstructor() {
+        AuthProviderStub ap = new AuthProviderStub("name", 1.0, "info");
+        assertEquals("name", ap.getName());
+        assertEquals(1.0, ap.getVersion());
+        assertEquals("info", ap.getInfo());
+        assertNotNull(ap.getServices());
+        assertTrue(ap.getServices().isEmpty());
+        
+        try {
+            new AuthProviderStub(null, -1.0, null);
+        } catch (Exception e) {
+            fail("unexpected exception");
+        }
+    }
+    
+    private class AuthProviderStub extends AuthProvider {
+        public AuthProviderStub(String name, double version, String info) {
+            super( name,  version, info);
+        }
+        public void login(Subject subject, CallbackHandler handler) {
+            
+        }
+        public void logout() {
+            
+        }
+        public void setCallbackHandler(CallbackHandler handler){
+            
+        }
+
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/BasicPermission2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/BasicPermission2Test.java
new file mode 100644
index 0000000..de99a0b
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/BasicPermission2Test.java
@@ -0,0 +1,122 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.BasicPermission;
+import java.security.PermissionCollection;
+
+public class BasicPermission2Test extends junit.framework.TestCase {
+
+    public static class BasicPermissionSubclass extends BasicPermission {
+        public BasicPermissionSubclass(String name) {
+            super(name);
+        }
+
+        public BasicPermissionSubclass(String name, String actions) {
+            super(name, actions);
+        }
+    }
+
+    BasicPermission bp = new BasicPermissionSubclass("aName");
+
+    BasicPermission bp2 = new BasicPermissionSubclass("aName", "anAction");
+
+    BasicPermission bp3 = new BasicPermissionSubclass("*");
+
+    BasicPermission bp4 = new BasicPermissionSubclass("this.that");
+
+    BasicPermission bp5 = new BasicPermissionSubclass("this.*");
+
+    /**
+     * @tests java.security.BasicPermission#BasicPermission(java.lang.String)
+     */
+    public void test_ConstructorLjava_lang_String() {
+        // Test for method java.security.BasicPermission(java.lang.String)
+        assertEquals("Incorrect name returned", "aName", bp.getName());
+    }
+
+    /**
+     * @tests java.security.BasicPermission#BasicPermission(java.lang.String,
+     *        java.lang.String)
+     */
+    public void test_ConstructorLjava_lang_StringLjava_lang_String() {
+        // Test for method java.security.BasicPermission(java.lang.String,
+        // java.lang.String)
+        assertEquals("Incorrect name returned", "aName", bp2.getName());
+    }
+
+    /**
+     * @tests java.security.BasicPermission#equals(java.lang.Object)
+     */
+    public void test_equalsLjava_lang_Object() {
+        // Test for method boolean
+        // java.security.BasicPermission.equals(java.lang.Object)
+        assertTrue("a) Equal objects returned non-equal", bp.equals(bp2));
+        assertTrue("b) Equal objects returned non-equal", bp2.equals(bp));
+        assertTrue("a) Unequal objects returned equal", !bp.equals(bp3));
+        assertTrue("b) Unequal objects returned equal", !bp4.equals(bp5));
+    }
+
+    /**
+     * @tests java.security.BasicPermission#getActions()
+     */
+    public void test_getActions() {
+        // Test for method java.lang.String
+        // java.security.BasicPermission.getActions()
+        assertTrue("a) Incorrect actions returned, wanted the empty String", bp
+                .getActions().equals(""));
+        assertTrue("b) Incorrect actions returned, wanted the empty String",
+                bp2.getActions().equals(""));
+    }
+
+    /**
+     * @tests java.security.BasicPermission#hashCode()
+     */
+    public void test_hashCode() {
+        // Test for method int java.security.BasicPermission.hashCode()
+        assertTrue("Equal objects should return same hash",
+                bp.hashCode() == bp2.hashCode());
+    }
+
+    /**
+     * @tests java.security.BasicPermission#implies(java.security.Permission)
+     */
+    public void test_impliesLjava_security_Permission() {
+        // Test for method boolean
+        // java.security.BasicPermission.implies(java.security.Permission)
+        assertTrue("Equal objects should imply each other", bp.implies(bp2));
+        assertTrue("a) should not imply", !bp.implies(bp3));
+        assertTrue("b) should not imply", !bp4.implies(bp5));
+        assertTrue("a) should imply", bp3.implies(bp5));
+        assertTrue("b) should imply", bp5.implies(bp4));
+
+    }
+
+    /**
+     * @tests java.security.BasicPermission#newPermissionCollection()
+     */
+    public void test_newPermissionCollection() {
+        // Test for method java.security.PermissionCollection
+        // java.security.BasicPermission.newPermissionCollection()
+        PermissionCollection bpc = bp.newPermissionCollection();
+        bpc.add(bp5);
+        bpc.add(bp);
+        assertTrue("Should imply", bpc.implies(bp4));
+        assertTrue("Should not imply", !bpc.implies(bp3));
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/CodeSignerTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/CodeSignerTest.java
new file mode 100644
index 0000000..1061d91
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/CodeSignerTest.java
@@ -0,0 +1,132 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Astapchuk
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.CodeSigner;
+import java.security.Timestamp;
+import java.security.cert.CertPath;
+import java.util.Date;
+
+import org.apache.harmony.security.tests.support.TestCertUtils;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Unit test for CodeSigner. 
+ */
+
+public class CodeSignerTest extends TestCase {
+
+    /**
+     * Entry point for standalone runs.
+     * @param args command line arguments
+     */
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(CodeSignerTest.class);
+    }
+
+    private CertPath cpath = TestCertUtils.genCertPath(3, 0);
+    private Date now = new Date();
+
+    private Timestamp ts = new Timestamp(now, cpath);
+
+    /**
+     * must throw NPE if signerCertPath is null
+     */
+    public void testCodeSigner_00() {
+        try {
+            new CodeSigner(null, ts);
+            fail("must not accept null");
+        } catch (NullPointerException ex) {
+            /* it's ok */
+        }
+    }
+
+    /**
+     * timestamp can be null
+     */
+    public final void testCodeSigner_01() {
+        new CodeSigner(cpath, null);
+    }
+
+    /**
+     * Test various assertions about equals()
+     */
+    public final void testEqualsObject() {
+        
+        CodeSigner one = new CodeSigner(cpath, ts);
+        CodeSigner two = new CodeSigner(cpath, ts);
+        CodeSigner three = new CodeSigner(cpath, null);
+        
+        CertPath cpath2 = TestCertUtils.genCertPath(5, 3);
+        CodeSigner four = new CodeSigner(cpath2, null);
+
+        assertTrue(one.equals(one));
+        assertTrue(one.equals(two));
+        assertTrue(two.equals(one));
+        assertFalse(one.equals(three));
+        assertFalse(three.equals(one));
+        assertTrue(three.equals(three));
+        // different CertPaths
+        assertFalse( three.equals(four));
+        // special cases
+        assertFalse( one.equals(null) );
+        assertFalse( one.equals(new Object()) );
+    }
+
+    /**
+     * Tests CodeSigner.getSignerCertPath()
+     */
+    public void testGetSignerCertPath() {
+        assertSame(new CodeSigner(cpath, null).getSignerCertPath(), cpath);
+    }
+
+    /**
+     * Tests CodeSigner.getTimeStamp()
+     */
+    public void testGetTimestamp() {
+        assertNull(new CodeSigner(cpath, null).getTimestamp());
+        assertSame(new CodeSigner(cpath, ts).getTimestamp(), ts);
+    }
+
+    /**
+     * Tests CodeSigner.toString()
+     */
+    public void testToString() {
+        assertTrue(new CodeSigner(cpath, null).toString().contains(""));
+        assertTrue(new CodeSigner(cpath, ts).toString().contains(""));
+    }
+
+    /**
+     * Tests CodeSigner.hashCode()
+     */
+    public void testHashCode() {
+        CodeSigner cs1 = new CodeSigner(cpath, ts);
+        CodeSigner cs2 = new CodeSigner(cpath, ts);
+        CodeSigner cs3 = new CodeSigner(cpath, null);
+        
+        assertTrue(cs1.hashCode() == cs2.hashCode());
+        assertTrue(cs2.hashCode() != cs3.hashCode());
+    }
+
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/CodeSource2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/CodeSource2Test.java
new file mode 100644
index 0000000..6fe01a0
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/CodeSource2Test.java
@@ -0,0 +1,146 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.net.URL;
+import java.security.CodeSigner;
+import java.security.CodeSource;
+import java.security.Timestamp;
+import java.security.cert.CertPath;
+import java.security.cert.Certificate;
+import java.util.Arrays;
+import java.util.Date;
+
+import org.apache.harmony.security.tests.support.TestCertUtils;
+
+
+
+public class CodeSource2Test extends junit.framework.TestCase {
+
+    /**
+     * @throws Exception
+     * @tests java.security.CodeSource#CodeSource(java.net.URL,
+     *        java.security.cert.Certificate[])
+     */
+    public void test_ConstructorLjava_net_URL$Ljava_security_cert_Certificate()
+            throws Exception {
+        // Test for method java.security.CodeSource(java.net.URL,
+        // java.security.cert.Certificate [])
+        new CodeSource(new java.net.URL("file:///test"), (Certificate[]) null);
+    }
+
+    /**
+     * @throws Exception
+     * @tests java.security.CodeSource#CodeSource(java.net.URL,
+     *        java.security.CodeSigner[])
+     */
+    public void test_ConstructorLjava_net_URL$Ljava_security_CodeSigner() {
+        // Test for method java.security.CodeSource(java.net.URL,
+        // java.security.cert.CodeSigner [])
+        try {
+            new CodeSource(new URL("file:///test"), (CodeSigner[]) null);
+        } catch (Exception e) {
+            fail("Unexpected Exception");
+        }
+
+        try {
+            new CodeSource(null, (CodeSigner[]) null);
+        } catch (Exception e) {
+            fail("Unexpected Exception");
+        }
+
+        CertPath cpath = TestCertUtils.genCertPath(3, 0);
+        Date now = new Date();
+
+        Timestamp ts = new Timestamp(now, cpath);
+        CodeSigner cs = new CodeSigner(cpath, ts);
+        try {
+            CodeSource codeSource = new CodeSource(new URL("file:///test"), new CodeSigner[] { cs });
+            assertNotNull(codeSource.getCertificates());
+            assertNotNull(codeSource.getCodeSigners());
+            assertTrue(Arrays.equals(new CodeSigner[] { cs }, codeSource.getCodeSigners()));
+            assertEquals(new URL("file:///test"), codeSource.getLocation());
+        } catch (Exception e) {
+            fail("Unexpected Exception");
+        }
+    }
+
+    /**
+     * @tests java.security.CodeSource#equals(java.lang.Object)
+     */
+    public void test_equalsLjava_lang_Object() throws Exception {
+        // Test for method boolean
+        // java.security.CodeSource.equals(java.lang.Object)
+        CodeSource cs1 = new CodeSource(new java.net.URL("file:///test"),
+                (Certificate[]) null);
+        CodeSource cs2 = new CodeSource(new java.net.URL("file:///test"),
+                (Certificate[]) null);
+        assertTrue("Identical objects were not equal()!", cs1.equals(cs2));
+    }
+
+    /**
+     * @tests java.security.CodeSource#hashCode()
+     */
+    public void test_hashCode() throws Exception {
+        URL url = new java.net.URL("file:///test");
+        CodeSource cs = new CodeSource(url, (Certificate[]) null);
+        assertTrue("Did not get expected hashCode!", cs.hashCode() == url
+                .hashCode());
+    }
+
+    /**
+     * @tests java.security.CodeSource#getCertificates()
+     */
+    public void test_getCertificates() throws Exception {
+        CodeSource cs = new CodeSource(new java.net.URL("file:///test"),
+                (Certificate[]) null);
+        assertNull("Should have gotten null certificate list.", cs
+                .getCertificates());
+    }
+
+    /**
+     * @tests java.security.CodeSource#getLocation()
+     */
+    public void test_getLocation() throws Exception {
+        // Test for method java.net.URL java.security.CodeSource.getLocation()
+        CodeSource cs = new CodeSource(new java.net.URL("file:///test"),
+                (Certificate[]) null);
+        assertEquals("Did not get expected location!", "file:/test", cs
+                .getLocation().toString());
+    }
+
+    /**
+     * @tests java.security.CodeSource#implies(java.security.CodeSource)
+     */
+    public void test_impliesLjava_security_CodeSource() throws Exception {
+        // Test for method boolean
+        // java.security.CodeSource.implies(java.security.CodeSource)
+        CodeSource cs1 = new CodeSource(new URL("file:/d:/somedir"),
+                (Certificate[]) null);
+        CodeSource cs2 = new CodeSource(new URL("file:/d:/somedir/"),
+                (Certificate[]) null);
+        assertTrue("Does not add /", cs1.implies(cs2));
+
+        cs1 = new CodeSource(new URL("file", null, -1, "/d:/somedir/"),
+                (Certificate[]) null);
+        cs2 = new CodeSource(new URL("file:/d:/somedir/"), (Certificate[]) null);
+        assertTrue("null host should imply host", cs1.implies(cs2));
+        assertTrue("host should not imply null host", !cs2.implies(cs1));
+    }
+
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/CodeSourceTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/CodeSourceTest.java
new file mode 100644
index 0000000..010f687
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/CodeSourceTest.java
@@ -0,0 +1,629 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Astapchuk
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.io.File;
+import java.net.URL;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.UnknownHostException;
+import java.security.CodeSigner;
+import java.security.CodeSource;
+import java.security.cert.CertPath;
+import java.security.cert.Certificate;
+
+import org.apache.harmony.security.tests.support.TestCertUtils;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Unit test for CodeSource.
+ * 
+ */
+
+public class CodeSourceTest extends TestCase {
+    /**
+     * 
+     * Entry point for standalone runs.
+     *
+     * @param args command line arguments
+     */
+    public static void main(String[] args) throws Exception {
+        junit.textui.TestRunner.run(CodeSourceTest.class);
+    }
+
+    private java.security.cert.Certificate[] chain = null;
+
+    /* Below are various URLs used during the testing */
+    private static URL urlSite;
+
+    private static URL urlDir; // must NOT end with '/'
+
+    private static URL urlDirOtherSite; // same as urlDir, but another site
+
+    private static URL urlDir_port80, urlDir_port81;
+
+    /* must be exactly the same as urlDir, but with slash added */
+    private static URL urlDirWithSlash;
+
+    //private static URL urlDirFtp;
+    private static URL urlDir_FileProtocol;
+
+    private static URL urlDirIP;
+
+    private static URL urlFile, urlFileWithAdditionalDirs, urlFileDirOtherDir;
+
+    private static URL urlFileDirMinus;
+
+    private static URL urlFileDirStar;
+
+    private static URL urlRef1, urlRef2;
+
+    static {
+        try {
+            String siteName = "www.intel.com";
+            InetAddress addr = InetAddress.getByName(siteName);
+            String siteIP = addr.getHostAddress();
+
+            urlSite = new URL("http://"+siteName+"");
+            urlDir = new URL("http://"+siteName+"/drl_test");
+            urlDirOtherSite = new URL("http://www.any-other-site-which-is-not-siteName.com/drl_test");
+
+            urlDir_port80 = new URL("http://"+siteName+":80/drl_test");
+            urlDir_port81 = new URL("http://"+siteName+":81/drl_test");
+            urlDirWithSlash = new URL(urlDir + "/");
+
+            //urlDirFtp = new URL("ftp://www.intel.com/drl_test");
+            urlDir_FileProtocol = new URL("file://"+siteName+"/drl_test");
+
+            urlDirIP = new URL("http://"+siteIP+"/drl_test");
+
+            urlFile = new URL("http://"+siteName+"/drl_test/empty.jar");
+            urlFileWithAdditionalDirs = new URL(
+                    "http://"+siteName+"/drl_test/what/ever/here/empty.jar");
+
+            urlFileDirMinus = new URL("http://"+siteName+"/drl_test/-");
+            urlFileDirStar = new URL("http://"+siteName+"/drl_test/*");
+            urlFileDirOtherDir = new URL("http://"+siteName+"/_test_drl_/*");
+
+            urlRef1 = new URL("http://"+siteName+"/drl_test/index.html#ref1");
+            urlRef2 = new URL("http://"+siteName+"/drl_test/index.html#ref2");
+        } catch (MalformedURLException ex) {
+            throw new Error(ex);
+        } catch (UnknownHostException ex) {
+            throw new Error(ex);
+        }
+    }
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        chain = TestCertUtils.getCertChain();
+    }
+
+    /**
+     * Tests hashCode().<br>
+     * javadoc says nothing, so test DRL-specific implementation. 
+     */
+    public void testHashCode() {
+        // when nothing is specified, then hashCode obviously must be 0. 
+        assertTrue(new CodeSource(null, (Certificate[]) null).hashCode() == 0);
+        // only URL.hashCode is taken into account...
+        assertTrue(new CodeSource(urlSite, (Certificate[]) null).hashCode() == urlSite
+                .hashCode());
+        // ... and certs[] does not affect it
+        assertTrue(new CodeSource(urlSite, chain).hashCode() == urlSite
+                .hashCode());
+    }
+
+    /**
+     * Tests CodeSource(URL, Certificate[]).
+     */
+    public void testCodeSourceURLCertificateArray() {
+        new CodeSource(null, (Certificate[]) null);
+        new CodeSource(urlSite, (Certificate[]) null);
+        new CodeSource(null, chain);
+        new CodeSource(urlSite, chain);
+    }
+
+    /**
+     * Tests CodeSource(URL, CodeSigner[]).
+     */
+    public void testCodeSourceURLCodeSignerArray() {
+        if (!has_15_features()) {
+            return;
+        }
+        new CodeSource(null, (CodeSigner[]) null);
+
+    }
+
+    /**
+     * equals(Object) must return <code>false</code> for null
+     */
+    public void testEqualsObject_00() {
+        CodeSource thiz = new CodeSource(urlSite, (Certificate[]) null);
+        assertFalse(thiz.equals(null));
+
+    }
+
+    /**
+     * equals(Object) must return <code>true</code> for the same object
+     */
+    public void testEqualsObject_01() {
+        CodeSource thiz = new CodeSource(urlSite, (Certificate[]) null);
+        assertTrue(thiz.equals(thiz));
+    }
+
+    /**
+     * Test for equals(Object)<br>
+     * The signer certificate chain must contain the same set of certificates, but 
+     * the order of the certificates is not taken into account.
+     */
+    public void testEqualsObject_02() {
+        Certificate cert0 = new TestCertUtils.TestCertificate();
+        Certificate cert1 = new TestCertUtils.TestCertificate();
+        Certificate[] certs0 = new Certificate[] { cert0, cert1 };
+        Certificate[] certs1 = new Certificate[] { cert1, cert0 };
+        CodeSource thiz = new CodeSource(urlSite, certs0);
+        CodeSource that = new CodeSource(urlSite, certs1);
+        assertTrue(thiz.equals(that));
+    }
+
+    /**
+     * Test for equals(Object)<br>
+     * Checks that both 'null' and not-null URLs are taken into account - properly. 
+     */
+    public void testEqualsObject_04() {
+        CodeSource thiz = new CodeSource(urlSite, (Certificate[]) null);
+        CodeSource that = new CodeSource(null, (Certificate[]) null);
+        assertFalse(thiz.equals(that));
+        assertFalse(that.equals(thiz));
+
+        that = new CodeSource(urlFile, (Certificate[]) null);
+        assertFalse(thiz.equals(that));
+        assertFalse(that.equals(thiz));
+    }
+
+    /**
+     * Tests CodeSource.getCertificates().
+     */
+    public void testGetCertificates_00() {
+        assertNull(new CodeSource(null, (Certificate[]) null).getCertificates());
+        java.security.cert.Certificate[] got = new CodeSource(null, chain)
+                .getCertificates();
+        // The returned array must be clone()-d ...
+        assertNotSame(got, chain);
+        // ... but must represent the same set of certificates
+        assertTrue(checkEqual(got, chain));
+    }
+
+    /**
+     * Tests whether the getCertificates() returns certificates obtained from 
+     * the signers.
+     */
+    public void testGetCertificates_01() {
+        if (!has_15_features()) {
+            return;
+        }
+        CertPath cpath = TestCertUtils.getCertPath();
+        Certificate[] certs = (Certificate[]) cpath.getCertificates().toArray();
+        CodeSigner[] signers = { new CodeSigner(cpath, null) };
+        CodeSource cs = new CodeSource(null, signers);
+        Certificate[] got = cs.getCertificates();
+        // The set of certificates must be exactly the same, 
+        // but the order is not specified
+        assertTrue(presented(certs, got));
+        assertTrue(presented(got, certs));
+    }
+
+    /**
+     * Checks whether two arrays of certificates represent the same same set of 
+     * certificates - in the same order.
+     * @param one first array 
+     * @param two second array
+     * @return <code>true</code> if both arrays represent the same set of 
+     * certificates, 
+     * <code>false</code> otherwise.
+     */
+    private static boolean checkEqual(java.security.cert.Certificate[] one,
+            java.security.cert.Certificate[] two) {
+
+        if (one == null) {
+            return two == null;
+        }
+
+        if (two == null) {
+            return false;
+        }
+
+        if (one.length != two.length) {
+            return false;
+        }
+
+        for (int i = 0; i < one.length; i++) {
+            if (one[i] == null) {
+                if (two[i] != null) {
+                    return false;
+                }
+            } else {
+                if (!one[i].equals(two[i])) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Performs a test whether the <code>what</code> certificates are all
+     * presented in <code>where</code> certificates.
+     * 
+     * @param what - first array of Certificates
+     * @param where  - second array of Certificates
+     * @return <code>true</code> if each and every certificate from 'what' 
+     * (including null) is presented in 'where' <code>false</code> otherwise
+     */
+    private static boolean presented(Certificate[] what, Certificate[] where) {
+        boolean whereHasNull = false;
+        for (int i = 0; i < what.length; i++) {
+            if (what[i] == null) {
+                if (whereHasNull) {
+                    continue;
+                }
+                for (int j = 0; j < where.length; j++) {
+                    if (where[j] == null) {
+                        whereHasNull = true;
+                        break;
+                    }
+                }
+                if (!whereHasNull) {
+                    return false;
+                }
+            } else {
+                boolean found = false;
+                for (int j = 0; j < where.length; j++) {
+                    if (what[i].equals(where[j])) {
+                        found = true;
+                        break;
+                    }
+                }
+                if (!found) {
+                    return false;
+                }
+            }
+
+        }
+        return true;
+    }
+
+    /**
+     * Tests CodeSource.getCodeSigners().
+     */
+    public void testGetCodeSigners_00() {
+        if (!has_15_features()) {
+            return;
+        }
+        CodeSigner[] signers = { new CodeSigner(TestCertUtils.getCertPath(),
+                null) };
+        CodeSource cs = new CodeSource(null, signers);
+        CodeSigner[] got = cs.getCodeSigners();
+        assertNotNull(got);
+        assertTrue(signers.length == got.length);
+        // not sure whether they must be in the same order
+        for (int i = 0; i < signers.length; i++) {
+            CodeSigner s = signers[i];
+            boolean found = false;
+            for (int j = 0; j < got.length; j++) {
+                if (got[j] == s) {
+                    found = true;
+                    break;
+                }
+            }
+            assertTrue(found);
+        }
+    }
+    
+    public void testGetCoderSignersNull() throws Exception{
+        assertNull(new CodeSource(new URL("http://url"), (Certificate[])null).getCodeSigners()); //$NON-NLS-1$
+    }
+
+    /**
+     * Tests CodeSource.getLocation()
+     */
+    public void testGetLocation() {
+        assertTrue(new CodeSource(urlSite, (Certificate[]) null).getLocation() == urlSite);
+        assertTrue(new CodeSource(urlSite, chain).getLocation() == urlSite);
+        assertNull(new CodeSource(null, (Certificate[]) null).getLocation());
+        assertNull(new CodeSource(null, chain).getLocation());
+    }
+
+    /**
+     * Tests CodeSource.toString()
+     */
+    public void testToString() {
+        // Javadoc keeps silence about String's format, 
+        // just make sure it can be invoked.
+        new CodeSource(urlSite, chain).toString();
+        new CodeSource(null, chain).toString();
+        new CodeSource(null, (Certificate[]) null).toString();
+    }
+
+    /**
+     * Tests whether we are running with the 1.5 features.<br>
+     * The test is preformed by looking for (via reflection) the CodeSource's 
+     * constructor  {@link CodeSource#CodeSource(URL, CodeSigner[])}.
+     * @return <code>true</code> if 1.5 feature is presented, <code>false</code> 
+     * otherwise.
+     */
+    private static boolean has_15_features() {
+        Class klass = CodeSource.class;
+        Class[] ctorArgs = { URL.class, new CodeSigner[] {}.getClass() };
+        try {
+            klass.getConstructor(ctorArgs);
+        } catch (NoSuchMethodException ex) {
+            // NoSuchMethod == Not RI.v1.5 and not DRL 
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * must not imply null CodeSource
+     */
+    public void testImplies_00() {
+        CodeSource cs0 = new CodeSource(null, (Certificate[]) null);
+        assertFalse(cs0.implies(null));
+    }
+
+    /**
+     * CodeSource with location=null && Certificate[] == null implies any other
+     * CodeSource
+     */
+    public void testImplies_01() throws Exception {
+        CodeSource thizCS = new CodeSource(urlSite, (Certificate[]) null);
+        CodeSource thatCS = new CodeSource(null, (Certificate[]) null);
+        assertTrue(thatCS.implies(thizCS));
+        assertTrue(thatCS.implies(thatCS));
+
+        assertFalse(thizCS.implies(thatCS));
+    }
+
+    /**
+     * If this object's location equals codesource's location, then return true.
+     */
+    public void testImplies_02() throws Exception {
+        CodeSource thizCS = new CodeSource(urlSite, (Certificate[]) null);
+        CodeSource thatCS = new CodeSource(thizCS.getLocation(),
+                (Certificate[]) null);
+        assertTrue(thizCS.implies(thatCS));
+        assertTrue(thatCS.implies(thizCS));
+
+    }
+
+    /**
+     * This object's protocol (getLocation().getProtocol()) must be equal to
+     * codesource's protocol.
+     */
+    /*
+     * FIXME
+     * commented out for temporary, as there is no FTP:// protocol supported yet.
+     * to be uncommented back.
+     public void testImplies_03() throws Exception {
+     CodeSource thizCS = new CodeSource(urlDir, (Certificate[]) null);
+     CodeSource thatCS = new CodeSource(urlDirFtp, (Certificate[]) null);
+     assertFalse(thizCS.implies(thatCS));
+     assertFalse(thatCS.implies(thizCS));
+     }
+     */
+
+    public void testImplies_03_tmp() throws Exception {
+        CodeSource thizCS = new CodeSource(urlDir, (Certificate[]) null);
+        CodeSource thatCS = new CodeSource(urlDir_FileProtocol,
+                (Certificate[]) null);
+        assertFalse(thizCS.implies(thatCS));
+        assertFalse(thatCS.implies(thizCS));
+    }
+
+    /**
+     * If this object's host (getLocation().getHost()) is not null, then the
+     * SocketPermission constructed with this object's host must imply the
+     * SocketPermission constructed with codesource's host.
+     */
+    public void testImplies_04() throws Exception {
+        CodeSource thizCS = new CodeSource(urlDir, (Certificate[]) null);
+        CodeSource thatCS = new CodeSource(urlDirIP, (Certificate[]) null);
+
+        assertTrue(thizCS.implies(thatCS));
+        assertTrue(thatCS.implies(thizCS));
+
+        // 
+        // Check for another site - force to create SocketPermission
+        //
+        thatCS = new CodeSource(urlDirOtherSite, (Certificate[]) null);
+        assertFalse(thizCS.implies(thatCS));
+
+        //
+        // also check for getHost() == null
+        //
+        thizCS = new CodeSource(new URL("http", null, "file1"),
+                (Certificate[]) null);
+        thatCS = new CodeSource(new URL("http", "another.host.com", "file1"),
+                (Certificate[]) null);
+        // well, yes, this is accordint to the spec...
+        assertTrue(thizCS.implies(thatCS));
+        assertFalse(thatCS.implies(thizCS));
+    }
+
+    /**
+     * If this object's port (getLocation().getPort()) is not equal to -1 (that
+     * is, if a port is specified), it must equal codesource's port.
+     */
+    public void testImplies_05() throws Exception {
+        CodeSource thizCS = new CodeSource(urlDir_port80, (Certificate[]) null);
+        CodeSource thatCS = new CodeSource(urlDir, (Certificate[]) null);
+
+        assertTrue(thizCS.implies(thatCS));
+        assertTrue(thatCS.implies(thizCS));
+
+        thizCS = new CodeSource(urlDir, (Certificate[]) null);
+        thatCS = new CodeSource(urlDir_port81, (Certificate[]) null);
+        //assert*True* because thizCS has 'port=-1'
+        assertTrue(thizCS.implies(thatCS));
+
+        thizCS = new CodeSource(urlDir_port81, (Certificate[]) null);
+        thatCS = new CodeSource(urlDir, (Certificate[]) null);
+        assertFalse(thizCS.implies(thatCS));
+        //
+        thizCS = new CodeSource(urlDir_port80, (Certificate[]) null);
+        thatCS = new CodeSource(urlDir_port81, (Certificate[]) null);
+        assertFalse(thizCS.implies(thatCS));
+    }
+
+    /**
+     * If this object's file (getLocation().getFile()) doesn't equal
+     * codesource's file, then the following checks are made: ...
+     */
+    public void testImplies_06() throws Exception {
+        CodeSource thizCS = new CodeSource(urlFile, (Certificate[]) null);
+        CodeSource thatCS = new CodeSource(urlFile, (Certificate[]) null);
+        assertTrue(thizCS.implies(thatCS));
+    }
+
+    /**
+     * ... If this object's file ends with "/-", then codesource's file must
+     * start with this object's file (exclusive the trailing "-").
+     */
+    public void testImplies_07() throws Exception {
+        CodeSource thiz = new CodeSource(urlFileDirMinus, (Certificate[]) null);
+        CodeSource that = new CodeSource(urlFile, (Certificate[]) null);
+        assertTrue(thiz.implies(that));
+
+        that = new CodeSource(urlFileWithAdditionalDirs, (Certificate[]) null);
+        assertTrue(thiz.implies(that));
+
+        that = new CodeSource(urlFileDirOtherDir, (Certificate[]) null);
+        assertFalse(thiz.implies(that));
+    }
+
+    /**
+     * ... If this object's file ends with a "/*", then codesource's file must
+     * start with this object's file and must not have any further "/"
+     * separators.
+     */
+    public void testImplies_08() throws Exception {
+        CodeSource thiz = new CodeSource(urlFileDirStar, (Certificate[]) null);
+        CodeSource that = new CodeSource(urlFile, (Certificate[]) null);
+        assertTrue(thiz.implies(that));
+        that = new CodeSource(urlFileWithAdditionalDirs, (Certificate[]) null);
+        assertFalse(thiz.implies(that));
+        //
+        that = new CodeSource(urlFileDirOtherDir, (Certificate[]) null);
+        assertFalse(thiz.implies(that));
+        // must not have any further '/'
+        that = new CodeSource(new URL(urlFile.toString() + "/"),
+                (Certificate[]) null);
+        assertFalse(thiz.implies(that));
+    }
+
+    /**
+     * ... If this object's file doesn't end with a "/", then codesource's file
+     * must match this object's file with a '/' appended.
+     */
+    public void testImplies_09() throws Exception {
+        CodeSource thizCS = new CodeSource(urlDir, (Certificate[]) null);
+        CodeSource thatCS = new CodeSource(urlDirWithSlash,
+                (Certificate[]) null);
+        assertTrue(thizCS.implies(thatCS));
+        assertFalse(thatCS.implies(thizCS));
+    }
+
+    /**
+     * If this object's reference (getLocation().getRef()) is not null, it must
+     * equal codesource's reference.
+     */
+    public void testImplies_0A() throws Exception {
+        CodeSource thizCS = new CodeSource(urlRef1, (Certificate[]) null);
+        CodeSource thatCS = new CodeSource(urlRef1, (Certificate[]) null);
+        assertTrue(thizCS.implies(thatCS));
+
+        thizCS = new CodeSource(urlRef1, (Certificate[]) null);
+        thatCS = new CodeSource(urlRef2, (Certificate[]) null);
+        assertFalse(thizCS.implies(thatCS));
+
+    }
+
+    /**
+     * If this certificates are not null, then all of this certificates should
+     * be presented in certificates of that codesource.
+     */
+    public void testImplies_0B() {
+
+        Certificate c0 = new TestCertUtils.TestCertificate("00");
+        Certificate c1 = new TestCertUtils.TestCertificate("01");
+        Certificate c2 = new TestCertUtils.TestCertificate("02");
+        Certificate[] thizCerts = { c0, c1 };
+        Certificate[] thatCerts = { c1, c0, c2 };
+
+        CodeSource thiz = new CodeSource(urlSite, thizCerts);
+        CodeSource that = new CodeSource(urlSite, thatCerts);
+        // two CodeSource-s with different set of certificates
+        assertTrue(thiz.implies(that));
+
+        //
+        that = new CodeSource(urlSite, (Certificate[]) null);
+        // 'thiz' has set of certs, while 'that' has no certs. URL-s are the 
+        // same.
+        assertFalse(thiz.implies(that));
+        assertTrue(that.implies(thiz));
+    }
+
+    /**
+     * Testing with special URLs like 'localhost', 'file://' scheme ...
+     * These special URLs have a special processing in implies(), 
+     * so they need to be covered and performance need to be checked 
+     */
+    public void testImplies_0C() throws Exception {
+        URL url0 = new URL("http://localhost/someDir");
+        URL url1 = new URL("http://localhost/someOtherDir");
+
+        CodeSource thizCS = new CodeSource(url0, (Certificate[]) null);
+        CodeSource thatCS = new CodeSource(url1, (Certificate[]) null);
+        assertFalse(thizCS.implies(thatCS));
+        assertFalse(thatCS.implies(thizCS));
+    }
+
+    /**
+     * Testing with special URLs like 'localhost', 'file://' scheme ...
+     * These special URLs have a special processing in implies(), 
+     * so they need to be covered and performance need to be checked 
+     */
+    public void testImplies_0D() throws Exception {
+        URL url0 = new URL("file:///" + System.getProperty("user.home")
+                + File.separator + "someDir");
+        URL url1 = new URL("file:///" + System.getProperty("user.home")
+                + File.separator + "someOtherDir");
+        CodeSource thizCS = new CodeSource(url0, (Certificate[]) null);
+        CodeSource thatCS = new CodeSource(url1, (Certificate[]) null);
+        assertFalse(thizCS.implies(thatCS));
+        assertFalse(thatCS.implies(thizCS));
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/DigestException2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/DigestException2Test.java
new file mode 100644
index 0000000..cfadaed
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/DigestException2Test.java
@@ -0,0 +1,43 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.DigestException;
+
+public class DigestException2Test extends junit.framework.TestCase {
+
+    /**
+     * @tests java.security.DigestException#DigestException()
+     */
+    public void test_Constructor() {
+        // Test for method java.security.DigestException()
+        DigestException de = new DigestException();
+        assertNull("Exception with no message should yield null message.", de
+                .getMessage());
+    }
+
+    /**
+     * @tests java.security.DigestException#DigestException(java.lang.String)
+     */
+    public void test_ConstructorLjava_lang_String() {
+        // Test for method java.security.DigestException(java.lang.String)
+        DigestException de = new DigestException("Test message");
+        assertEquals("Exception message is incorrect", "Test message", de
+                .getMessage());
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/DigestExceptionTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/DigestExceptionTest.java
new file mode 100644
index 0000000..5cefbe0
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/DigestExceptionTest.java
@@ -0,0 +1,186 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.DigestException;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>DigestException</code> class constructors and methods.
+ * 
+ */
+public class DigestExceptionTest extends TestCase {
+
+    public static void main(String[] args) {
+    }
+
+    /**
+     * Constructor for DigestExceptionTests.
+     * 
+     * @param arg0
+     */
+    public DigestExceptionTest(String arg0) {
+        super(arg0);
+    }
+
+    private static String[] msgs = {
+            "",
+            "Check new message",
+            "Check new message Check new message Check new message Check new message Check new message" };
+
+    private static Throwable tCause = new Throwable("Throwable for exception");
+
+    /**
+     * Test for <code>DigestException()</code> constructor Assertion:
+     * constructs DigestException with no detail message
+     */
+    public void testDigestException01() {
+        DigestException tE = new DigestException();
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>DigestException(String)</code> constructor Assertion:
+     * constructs DigestException with detail message msg. Parameter
+     * <code>msg</code> is not null.
+     */
+    public void testDigestException02() {
+        DigestException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new DigestException(msgs[i]);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+
+    /**
+     * Test for <code>DigestException(String)</code> constructor Assertion:
+     * constructs DigestException when <code>msg</code> is null
+     */
+    public void testDigestException03() {
+        String msg = null;
+        DigestException tE = new DigestException(msg);
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>DigestException(Throwable)</code> constructor Assertion:
+     * constructs DigestException when <code>cause</code> is null
+     */
+    public void testDigestException04() {
+        Throwable cause = null;
+        DigestException tE = new DigestException(cause);
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>DigestException(Throwable)</code> constructor Assertion:
+     * constructs DigestException when <code>cause</code> is not null
+     */
+    public void testDigestException05() {
+        DigestException tE = new DigestException(tCause);
+        if (tE.getMessage() != null) {
+            String toS = tCause.toString();
+            String getM = tE.getMessage();
+            assertTrue("getMessage() should contain ".concat(toS), (getM
+                    .indexOf(toS) != -1));
+        }
+        assertNotNull("getCause() must not return null", tE.getCause());
+        assertEquals("getCause() must return ".concat(tCause.toString()), tE
+                .getCause(), tCause);
+    }
+
+    /**
+     * Test for <code>DigestException(String, Throwable)</code> constructor
+     * Assertion: constructs DigestException when <code>cause</code> is null
+     * <code>msg</code> is null
+     */
+    public void testDigestException06() {
+        DigestException tE = new DigestException(null, null);
+        assertNull("getMessage() must return null", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>DigestException(String, Throwable)</code> constructor
+     * Assertion: constructs DigestException when <code>cause</code> is null
+     * <code>msg</code> is not null
+     */
+    public void testDigestException07() {
+        DigestException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new DigestException(msgs[i], null);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+
+    /**
+     * Test for <code>DigestException(String, Throwable)</code> constructor
+     * Assertion: constructs DigestException when <code>cause</code> is not
+     * null <code>msg</code> is null
+     */
+    public void testDigestException08() {
+        DigestException tE = new DigestException(null, tCause);
+        if (tE.getMessage() != null) {
+            String toS = tCause.toString();
+            String getM = tE.getMessage();
+            assertTrue("getMessage() must should ".concat(toS), (getM
+                    .indexOf(toS) != -1));
+        }
+        assertNotNull("getCause() must not return null", tE.getCause());
+        assertEquals("getCause() must return ".concat(tCause.toString()), tE
+                .getCause(), tCause);
+    }
+
+    /**
+     * Test for <code>DigestException(String, Throwable)</code> constructor
+     * Assertion: constructs DigestException when <code>cause</code> is not
+     * null <code>msg</code> is not null
+     */
+    public void testDigestException09() {
+        DigestException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new DigestException(msgs[i], tCause);
+            String getM = tE.getMessage();
+            String toS = tCause.toString();
+            if (msgs[i].length() > 0) {
+                assertTrue("getMessage() must contain ".concat(msgs[i]), getM
+                        .indexOf(msgs[i]) != -1);
+                if (!getM.equals(msgs[i])) {
+                    assertTrue("getMessage() should contain ".concat(toS), getM
+                            .indexOf(toS) != -1);
+                }
+            }
+            assertNotNull("getCause() must not return null", tE.getCause());
+            assertEquals("getCause() must return ".concat(tCause.toString()),
+                    tE.getCause(), tCause);
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/DigestInputStream2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/DigestInputStream2Test.java
new file mode 100644
index 0000000..5f7a3a8
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/DigestInputStream2Test.java
@@ -0,0 +1,165 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.DigestInputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+public class DigestInputStream2Test extends junit.framework.TestCase {
+
+    ByteArrayInputStream inStream;
+
+    ByteArrayInputStream inStream1;
+
+    MessageDigest digest;
+
+    /**
+     * @tests java.security.DigestInputStream#DigestInputStream(java.io.InputStream,
+     *        java.security.MessageDigest)
+     */
+    public void test_ConstructorLjava_io_InputStreamLjava_security_MessageDigest() {
+        // Test for method java.security.DigestInputStream(java.io.InputStream,
+        // java.security.MessageDigest)
+        DigestInputStream dis = new DigestInputStream(inStream, digest);
+        assertNotNull("Constructor returned null instance", dis);
+    }
+
+    /**
+     * @tests java.security.DigestInputStream#getMessageDigest()
+     */
+    public void test_getMessageDigest() {
+        // Test for method java.security.MessageDigest
+        // java.security.DigestInputStream.getMessageDigest()
+        DigestInputStream dis = new DigestInputStream(inStream, digest);
+        assertEquals("getMessageDigest returned a bogus result", digest, dis
+                .getMessageDigest());
+    }
+
+    /**
+     * @tests java.security.DigestInputStream#on(boolean)
+     */
+    public void test_onZ() throws Exception {
+        // Test for method void java.security.DigestInputStream.on(boolean)
+        MessageDigest originalDigest = (MessageDigest) (digest.clone());
+        MessageDigest noChangeDigest = (MessageDigest) (digest.clone());
+        DigestInputStream dis = new DigestInputStream(inStream, noChangeDigest);
+        // turn off processing
+        dis.on(false);
+        // read some data
+        int c = dis.read();
+        assertEquals('T', c);
+
+        // make sure the digest for the part where it was off has not
+        // changed
+        assertTrue("MessageDigest changed even though processing was off",
+                MessageDigest.isEqual(noChangeDigest.digest(), originalDigest
+                        .digest()));
+        MessageDigest changeDigest = (MessageDigest) (digest.clone());
+        dis = new DigestInputStream(inStream, digest);
+
+        // turn on processing
+        dis.on(true);
+        c = dis.read();
+        assertEquals('h', c);
+
+        // make sure the digest has changed
+        assertTrue("MessageDigest did not change with processing on",
+                !MessageDigest.isEqual(digest.digest(), changeDigest.digest()));
+    }
+
+    /**
+     * @tests java.security.DigestInputStream#read()
+     */
+    public void test_read() throws IOException {
+        // Test for method int java.security.DigestInputStream.read()
+        DigestInputStream dis = new DigestInputStream(inStream, digest);
+
+        // read and compare the data that the inStream has
+        int c;
+        while ((c = dis.read()) > -1) {
+            int d = inStream1.read();
+            assertEquals(d, c);
+        }// end while
+    }
+
+    /**
+     * @tests java.security.DigestInputStream#read(byte[], int, int)
+     */
+    public void test_read$BII() throws IOException {
+        // Test for method int java.security.DigestInputStream.read(byte [],
+        // int, int)
+        DigestInputStream dis = new DigestInputStream(inStream, digest);
+        int bytesToRead = inStream.available();
+        byte buf1[] = new byte[bytesToRead + 5];
+        byte buf2[] = new byte[bytesToRead + 5];
+        // make sure we're actually reading some data
+        assertTrue("No data to read for this test", bytesToRead>0);
+        
+        // read and compare the data that the inStream has
+        int bytesRead1 = dis.read(buf1, 5, bytesToRead);
+        int bytesRead2 = inStream1.read(buf2, 5, bytesToRead);
+        assertEquals("Didn't read the same from each stream", bytesRead1,
+                bytesRead2);
+        assertEquals("Didn't read the entire", bytesRead1, bytesToRead);
+        // compare the arrays
+        boolean same = true;
+        for (int i = 0; i < bytesToRead + 5; i++) {
+            if (buf1[i] != buf2[i]) {
+                same = false;
+            }
+        }// end for 
+        assertTrue("Didn't get the same data", same);
+    }
+
+    /**
+     * @tests java.security.DigestInputStream#setMessageDigest(java.security.MessageDigest)
+     */
+    public void test_setMessageDigestLjava_security_MessageDigest() {
+        // Test for method void
+        // java.security.DigestInputStream.setMessageDigest(java.security.MessageDigest)
+        DigestInputStream dis = new DigestInputStream(inStream, null);
+        
+        // make sure the digest is null when it's not been set
+        assertNull(
+                "Uninitialised MessageDigest should have been returned as null",
+                dis.getMessageDigest());
+        dis.setMessageDigest(digest);
+        assertEquals("Wrong MessageDigest was returned.", digest, dis
+                .getMessageDigest());
+    }
+
+    /**
+     * Sets up the fixture, for example, open a network connection. This method
+     * is called before a test is executed.
+     */
+    protected void setUp() {
+        // create a ByteArrayInputStream to perform digesting on
+        inStream = new ByteArrayInputStream(
+                "This is a test string for digesting".getBytes());
+        inStream1 = new ByteArrayInputStream(
+                "This is a test string for digesting".getBytes());
+        try {
+            digest = MessageDigest.getInstance("SHA-1");
+        } catch (NoSuchAlgorithmException e) {
+            fail("Unable to find SHA-1 algorithm");
+        }
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/DigestInputStreamTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/DigestInputStreamTest.java
new file mode 100644
index 0000000..af92e0b
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/DigestInputStreamTest.java
@@ -0,0 +1,584 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.DigestInputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+import org.apache.harmony.security.tests.support.MDGoldenData;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for fields and methods of class <code>DigestInputStream</code>
+ * 
+ */
+public class DigestInputStreamTest extends TestCase {
+
+    /**
+     * Message digest algorithm name used during testing
+     */
+    private static final String algorithmName[] = {
+            "SHA-1",
+            "SHA",
+            "SHA1",
+            "SHA-256",
+            "SHA-384",
+            "SHA-512",
+            "MD5",
+    };
+    /**
+     * Chunk size for read(byte, off, len) tests
+     */
+    private static final int CHUNK_SIZE = 32;
+    /**
+     * Test message for digest computations
+     */
+    private static final byte[] myMessage = MDGoldenData.getMessage();
+    /**
+     * The length of test message
+     */
+    private static final int MY_MESSAGE_LEN = myMessage.length;
+
+    /**
+     * Constructor for DigestInputStreamTest.
+     * @param name
+     */
+    public DigestInputStreamTest(String name) {
+        super(name);
+    }
+
+    //
+    // Tests
+    //
+
+    /**
+     * Test #1 for <code>DigestInputStream</code> constructor<br>
+     * 
+     * Assertion: creates new <code>DigestInputStream</code> instance
+     * using valid parameters (both non <code>null</code>)
+     *
+     * @throws NoSuchAlgorithmException
+     */
+    public final void testDigestInputStream01()  {
+        for (int i=0; i<algorithmName.length; i++) {
+            try {
+                MessageDigest md = MessageDigest.getInstance(algorithmName[i]);
+                InputStream is = new ByteArrayInputStream(myMessage);
+                InputStream dis = new DigestInputStream(is, md);
+                assertTrue(dis instanceof DigestInputStream);
+                return;
+            } catch (NoSuchAlgorithmException e) {
+                // allowed failure
+            }
+        }
+        fail(getName() + ": no MessageDigest algorithms available - test not performed");
+    }
+
+    /**
+     * Test #2 for <code>DigestInputStream</code> constructor<br>
+     * 
+     * Assertion: creates new <code>DigestInputStream</code> instance
+     * using valid parameters (both <code>null</code>)
+     */
+    public final void testDigestInputStream02() {
+        InputStream dis = new DigestInputStream(null, null);
+        assertTrue(dis instanceof DigestInputStream);
+    }
+
+    /**
+     * Test #1 for <code>read()</code> method<br>
+     * 
+     * Assertion: returns the byte read<br>
+     * Assertion: updates associated digest<br>
+     */
+    public final void testRead01()
+        throws IOException {
+        for (int ii=0; ii<algorithmName.length; ii++) {
+            try {
+                MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
+                InputStream is = new ByteArrayInputStream(myMessage);
+                DigestInputStream dis = new DigestInputStream(is, md);
+                for (int i=0; i<MY_MESSAGE_LEN; i++) {
+                    // check that read() returns valid values
+                    assertTrue("retval", ((byte)dis.read() == myMessage[i]));
+                }
+                // check that associated digest has been updated properly
+                assertTrue("update",
+                        Arrays.equals(
+                                dis.getMessageDigest().digest(),
+                                MDGoldenData.getDigest(algorithmName[ii])));
+                return;
+            } catch (NoSuchAlgorithmException e) {
+                // allowed failure
+            }
+        }
+        fail(getName() + ": no MessageDigest algorithms available - test not performed");
+    }
+
+    /**
+     * Test #2 for <code>read()</code> method<br>
+     * 
+     * Assertion: returns -1 if EOS had been
+     * reached but not read before method call<br>
+     * 
+     * Assertion: must not update digest if EOS had been
+     * reached but not read before method call<br>
+     */
+    public final void testRead02()
+        throws IOException {
+        for (int ii=0; ii<algorithmName.length; ii++) {
+            try {
+                MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
+                InputStream is = new ByteArrayInputStream(myMessage);
+                DigestInputStream dis = new DigestInputStream(is, md);
+                for (int i=0; i<MY_MESSAGE_LEN; i++) {
+                    dis.read();
+                }
+                // check that subsequent read() calls return -1 (eos)
+                assertEquals("retval1", -1, dis.read());
+                assertEquals("retval2", -1, dis.read());
+                assertEquals("retval3", -1, dis.read());
+                // check that 3 previous read() calls did not update digest
+                assertTrue("update",
+                        Arrays.equals(dis.getMessageDigest().digest(),
+                                MDGoldenData.getDigest(algorithmName[ii])));
+                return;
+            } catch (NoSuchAlgorithmException e) {
+                // allowed failure
+            }
+        }
+        fail(getName() + ": no MessageDigest algorithms available - test not performed");
+    }
+
+    /**
+     * Test #3 for <code>read()</code> method<br>
+     * Test #1 for <code>on(boolean)</code> method<br>
+     * 
+     * Assertion: <code>read()</code> must not update digest if it is off<br>
+     * Assertion: <code>on(boolean)</code> turns digest functionality on
+     * (if <code>true</code> passed as a parameter) or off (if <code>false</code>
+     *  passed)
+     */
+    public final void testRead03()
+        throws IOException {
+        for (int ii=0; ii<algorithmName.length; ii++) {
+            try {
+                MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
+                InputStream is = new ByteArrayInputStream(myMessage);
+                DigestInputStream dis = new DigestInputStream(is, md);
+                
+                // turn digest off
+                dis.on(false);
+                
+                for (int i=0; i<MY_MESSAGE_LEN; i++) {
+                    dis.read();
+                }
+                
+                // check that digest value has not been updated by read()
+                assertTrue(Arrays.equals(dis.getMessageDigest().digest(),
+                        MDGoldenData.getDigest(algorithmName[ii]+"_NU")));
+                return;
+            } catch (NoSuchAlgorithmException e) {
+                // allowed failure
+            }
+        }
+        fail(getName() + ": no MessageDigest algorithms available - test not performed");
+    }
+
+    /**
+     * Test #4 for <code>read()</code> method<br>
+     * 
+     * Assertion: broken <code>DigestInputStream</code>instance: 
+     * <code>InputStream</code> not set. <code>read()</code> must
+     * not work
+     */
+    public final void testRead04() throws IOException {
+        for (int ii=0; ii<algorithmName.length; ii++) {
+            try {
+                MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
+                DigestInputStream dis = new DigestInputStream(null, md);
+                // must result in an exception
+                try {
+                    for (int i=0; i<MY_MESSAGE_LEN; i++) {
+                        dis.read();
+                    }
+                } catch (Exception e) {
+                    return;
+                }
+
+                fail("InputStream not set. read() must not work");
+
+            } catch (NoSuchAlgorithmException e) {
+                // allowed failure
+            }
+        }
+        fail(getName() + ": no MessageDigest algorithms available - test not performed");
+    }
+
+    /**
+     * Test #5 for <code>read()</code> method<br>
+     * 
+     * Assertion: broken <code>DigestInputStream</code>instance: 
+     * associated <code>MessageDigest</code> not set.
+     * <code>read()</code> must not work when digest
+     * functionality is on
+     */
+    public final void testRead05() {
+        InputStream is = new ByteArrayInputStream(myMessage);
+        DigestInputStream dis = new DigestInputStream(is, null);
+
+        // must result in an exception
+        try {
+            for (int i=0; i<MY_MESSAGE_LEN; i++) {
+                dis.read();
+            }
+            fail("read() must not work when digest functionality is on");
+        } catch (Exception e) {
+        }
+    }
+
+    /**
+     * Test #6 for <code>read()</code> method<br>
+     * Test #2 for <code>on(boolean)</code> method<br>
+     * 
+     * Assertion: broken <code>DigestInputStream</code>instance:
+     * associated <code>MessageDigest</code> not set.
+     * <code>read()</code> must work when digest
+     * functionality is off
+     */
+    public final void testRead06()
+        throws IOException {
+        InputStream is = new ByteArrayInputStream(myMessage);
+        // construct object without digest
+        DigestInputStream dis = new DigestInputStream(is, null);
+        // set digest functionality to off
+        dis.on(false);
+        // the following must pass without any exception
+        for (int i=0; i<MY_MESSAGE_LEN; i++) {
+            assertTrue((byte)dis.read() == myMessage[i]);
+        }
+    }
+
+    /**
+     * Test #1 for <code>read(byte[],int,int)</code> method<br>
+     * 
+     * Assertion: returns the number of bytes read<br>
+     * 
+     * Assertion: put bytes read into specified array at specified offset<br>
+     * 
+     * Assertion: updates associated digest<br>
+     */
+    public final void testReadbyteArrayintint01()
+        throws IOException {        
+        for (int ii=0; ii<algorithmName.length; ii++) {
+            try {
+                MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
+                InputStream is = new ByteArrayInputStream(myMessage);
+                DigestInputStream dis = new DigestInputStream(is, md);
+                byte[] bArray = new byte[MY_MESSAGE_LEN];
+                
+                // check that read(byte[],int,int) returns valid value
+                assertTrue("retval",
+                        dis.read(bArray, 0, bArray.length) == MY_MESSAGE_LEN);
+                // check that bArray has been filled properly
+                assertTrue("bArray", Arrays.equals(myMessage, bArray));
+                // check that associated digest has been updated properly
+                assertTrue("update", Arrays.equals(dis.getMessageDigest().digest(),
+                        MDGoldenData.getDigest(algorithmName[ii])));
+                return;
+            } catch (NoSuchAlgorithmException e) {
+                // allowed failure
+            }
+        }
+        fail(getName() + ": no MessageDigest algorithms available - test not performed");
+    }
+
+    /**
+     * Test #2 for <code>read(byte[],int,int)</code> method<br>
+     * 
+     * Assertion: returns the number of bytes read<br>
+     * 
+     * Assertion: put bytes read into specified array at specified offset<br>
+     * 
+     * Assertion: updates associated digest<br>
+     */
+    public final void testReadbyteArrayintint02()
+        throws IOException {
+        // check precondition
+        assertEquals(0, MY_MESSAGE_LEN % CHUNK_SIZE);
+        
+        for (int ii=0; ii<algorithmName.length; ii++) {
+            try {
+                MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
+                InputStream is = new ByteArrayInputStream(myMessage);
+                DigestInputStream dis = new DigestInputStream(is, md);
+                byte[] bArray = new byte[MY_MESSAGE_LEN];
+                
+                for (int i=0; i<MY_MESSAGE_LEN/CHUNK_SIZE; i++) {
+                    // check that read(byte[],int,int) returns valid value
+                    assertTrue("retval",
+                            dis.read(bArray, i*CHUNK_SIZE, CHUNK_SIZE) == CHUNK_SIZE);
+                }
+                // check that bArray has been filled properly
+                assertTrue("bArray", Arrays.equals(myMessage, bArray));
+                // check that associated digest has been updated properly
+                assertTrue("update", Arrays.equals(dis.getMessageDigest().digest(),
+                        MDGoldenData.getDigest(algorithmName[ii])));
+                return;
+            } catch (NoSuchAlgorithmException e) {
+                // allowed failure
+            }
+        }
+        fail(getName() + ": no MessageDigest algorithms available - test not performed");
+    }
+
+
+    /**
+     * Test #3 for <code>read(byte[],int,int)</code> method<br>
+     * 
+     * Assertion: returns the number of bytes read<br>
+     * 
+     * Assertion: put bytes read into specified array at specified offset<br>
+     * 
+     * Assertion: updates associated digest<br>
+     */
+    public final void testReadbyteArrayintint03()
+        throws IOException {
+        // check precondition
+        assertTrue(MY_MESSAGE_LEN % (CHUNK_SIZE+1) != 0);
+        
+        for (int ii=0; ii<algorithmName.length; ii++) {
+            try {
+                MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
+                InputStream is = new ByteArrayInputStream(myMessage);
+                DigestInputStream dis = new DigestInputStream(is, md);
+                byte[] bArray = new byte[MY_MESSAGE_LEN];
+                
+                for (int i=0; i<MY_MESSAGE_LEN/(CHUNK_SIZE+1); i++) {
+                    // check that read(byte[],int,int) returns valid value
+                    assertTrue("retval1",
+                            dis.read(bArray, i*(CHUNK_SIZE+1), CHUNK_SIZE+1) ==
+                                CHUNK_SIZE + 1);
+                }
+                
+                // check that last call returns right
+                // number of remaining bytes
+                assertTrue("retval2",
+                        dis.read(bArray,
+                                MY_MESSAGE_LEN/(CHUNK_SIZE+1)*(CHUNK_SIZE+1),
+                                MY_MESSAGE_LEN % (CHUNK_SIZE+1)) ==
+                                    (MY_MESSAGE_LEN % (CHUNK_SIZE+1)));
+                
+                // check that bArray has been filled properly
+                assertTrue("bArray", Arrays.equals(myMessage, bArray));
+                // check that associated digest has been updated properly
+                assertTrue("update", Arrays.equals(dis.getMessageDigest().digest(),
+                        MDGoldenData.getDigest(algorithmName[ii])));
+                return;
+            } catch (NoSuchAlgorithmException e) {
+                // allowed failure
+            }
+        }
+        fail(getName() + ": no MessageDigest algorithms available - test not performed");
+    }
+
+    /**
+     * Test #4 for <code>read(byte[],int,int)</code> method<br>
+     * 
+     * Assertion: returns the number of bytes read<br>
+     * 
+     * Assertion: updates associated digest<br>
+     */
+    public final void testReadbyteArrayintint04()
+        throws IOException {        
+        for (int ii=0; ii<algorithmName.length; ii++) {
+            try {
+                MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
+                InputStream is = new ByteArrayInputStream(myMessage);
+                DigestInputStream dis = new DigestInputStream(is, md);
+                byte[] bArray = new byte[MY_MESSAGE_LEN];
+                // read all but EOS
+                dis.read(bArray, 0, bArray.length);
+                // check that subsequent read(byte[],int,int) calls return -1 (EOS)
+                assertEquals("retval1", -1, dis.read(bArray, 0, 1));
+                assertEquals("retval2", -1, dis.read(bArray, 0, bArray.length));
+                assertEquals("retval3", -1, dis.read(bArray, 0, 1));
+                // check that 3 previous read() calls did not update digest
+                assertTrue("update",
+                        Arrays.equals(dis.getMessageDigest().digest(),
+                                MDGoldenData.getDigest(algorithmName[ii])));
+                return;
+            } catch (NoSuchAlgorithmException e) {
+                // allowed failure
+            }
+        }
+        fail(getName() + ": no MessageDigest algorithms available - test not performed");
+    }
+
+    /**
+     * Test #5 for <code>read(byte[],int,int)</code> method<br>
+     * 
+     * Assertion: returns the number of bytes read<br>
+     * 
+     * Assertion: put bytes read into specified array at specified offset<br>
+     * 
+     * Assertion: does not update associated digest if
+     * digest functionality is off<br>
+     */
+    public final void testReadbyteArrayintint05()
+        throws IOException {
+        // check precondition
+        assertEquals(0, MY_MESSAGE_LEN % CHUNK_SIZE);
+        
+        for (int ii=0; ii<algorithmName.length; ii++) {
+            try {
+                MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
+                InputStream is = new ByteArrayInputStream(myMessage);
+                DigestInputStream dis = new DigestInputStream(is, md);
+                byte[] bArray = new byte[MY_MESSAGE_LEN];
+                
+                // turn digest off
+                dis.on(false);
+                
+                for (int i=0; i<MY_MESSAGE_LEN/CHUNK_SIZE; i++) {
+                    dis.read(bArray, i*CHUNK_SIZE, CHUNK_SIZE);
+                }
+                // check that digest has not been updated
+                assertTrue(Arrays.equals(dis.getMessageDigest().digest(),
+                        MDGoldenData.getDigest(algorithmName[ii]+"_NU")));
+                return;
+            } catch (NoSuchAlgorithmException e) {
+                // allowed failure
+            }
+        }
+        fail(getName() + ": no MessageDigest algorithms available - test not performed");
+    }
+
+    /**
+     * Test for <code>getMessageDigest()</code> method<br>
+     * 
+     * Assertion: returns associated message digest<br>
+     */
+    public final void testGetMessageDigest() {
+        for (int ii=0; ii<algorithmName.length; ii++) {
+            try {
+                MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
+                DigestInputStream dis = new DigestInputStream(null, md);
+                
+                assertTrue(dis.getMessageDigest() == md);
+                return;
+            } catch (NoSuchAlgorithmException e) {
+                // allowed failure
+            }
+        }
+        fail(getName() + ": no MessageDigest algorithms available - test not performed");
+    }
+
+
+    /**
+     * Test for <code>setMessageDigest()</code> method<br>
+     * 
+     * Assertion: set associated message digest<br>
+     */
+    public final void testSetMessageDigest() {
+        for (int ii=0; ii<algorithmName.length; ii++) {
+            try {
+                DigestInputStream dis = new DigestInputStream(null, null);
+                MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
+                dis.setMessageDigest(md);
+                
+                assertTrue(dis.getMessageDigest() == md);
+                return;
+            } catch (NoSuchAlgorithmException e) {
+                // allowed failure
+            }
+        }
+        fail(getName() + ": no MessageDigest algorithms available - test not performed");
+    }
+
+    /**
+     * Test for <code>on()</code> method<br>
+     * Assertion: turns digest functionality on or off
+     */
+    public final void testOn() throws IOException {
+        for (int ii=0; ii<algorithmName.length; ii++) {
+            try {
+                MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
+                InputStream is = new ByteArrayInputStream(myMessage);
+                DigestInputStream dis = new DigestInputStream(is, md);
+                
+                // turn digest off
+                dis.on(false);
+                
+                for (int i=0; i<MY_MESSAGE_LEN-1; i++) {
+                    dis.read();
+                }
+                
+                // turn digest on
+                dis.on(true);
+                
+                // read remaining byte
+                dis.read();
+                
+                byte[] digest = dis.getMessageDigest().digest();
+                
+                // check that digest value has been
+                // updated by the last read() call
+                assertFalse(
+                        Arrays.equals(digest,MDGoldenData.getDigest(algorithmName[ii])) ||
+                        Arrays.equals(digest,MDGoldenData.getDigest(algorithmName[ii]+"_NU")));
+                return;
+            } catch (NoSuchAlgorithmException e) {
+                // allowed failure
+            }
+        }
+        fail(getName() + ": no MessageDigest algorithms available - test not performed");
+    }
+
+    /**
+     * Test for <code>toString()</code> method<br>
+     * Assertion: returns <code>String</code> representation of this object
+     */
+    public final void testToString() {
+        for (int ii=0; ii<algorithmName.length; ii++) {
+            try {
+                MessageDigest md = MessageDigest.getInstance(algorithmName[ii]);
+                InputStream is = new ByteArrayInputStream(myMessage);
+                DigestInputStream dis = new DigestInputStream(is, md);
+
+                assertNotNull(dis.toString());
+                return;
+            } catch (NoSuchAlgorithmException e) {
+                // allowed failure
+            }
+        }
+        fail(getName() + ": no MessageDigest algorithms available - test not performed");
+    }
+
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/DigestOutputStreamTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/DigestOutputStreamTest.java
new file mode 100644
index 0000000..bff91a9
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/DigestOutputStreamTest.java
@@ -0,0 +1,610 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.DigestOutputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+import org.apache.harmony.security.tests.support.MDGoldenData;
+import org.apache.harmony.security.tests.support.MyMessageDigest1;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for fields and methods of class <code>DigestInputStream</code>
+ * 
+ */
+public class DigestOutputStreamTest extends TestCase {
+
+    /**
+     * Message digest algorithm name used during testing
+     */
+    private static final String algorithmName[] = {
+            "SHA-1",
+            "SHA",
+            "SHA1",
+            "SHA-256",
+            "SHA-384",
+            "SHA-512",
+            "MD5",
+    };
+    /**
+     * Chunk size for read(byte, off, len) tests
+     */
+    private static final int CHUNK_SIZE = 32;
+    /**
+     * Test message for digest computations
+     */
+    private static final byte[] myMessage = MDGoldenData.getMessage();
+    /**
+     * The length of test message
+     */
+    private static final int MY_MESSAGE_LEN = myMessage.length;
+
+    /**
+     * Constructor for DigestInputStreamTest.
+     * @param name
+     */
+    public DigestOutputStreamTest(String name) {
+        super(name);
+    }
+
+    //
+    // Tests
+    //
+
+    /**
+     * @tests java.security.DigestOutputStream#DigestOutputStream(java.io.OutputStream,
+     *        java.security.MessageDigest)
+     */
+    public void test_CtorLjava_io_OutputStreamLjava_security_MessageDigest() {
+
+        // non-null parameters
+        MessageDigest md = new MyMessageDigest1();
+        MyOutputStream out = new MyOutputStream();
+
+        MyDigestOutputStream dos = new MyDigestOutputStream(out, md);
+        assertSame(out, dos.myOutputStream());
+        assertSame(md, dos.myMessageDigest());
+
+        // null parameters
+        dos = new MyDigestOutputStream(null, null);
+        assertNull(dos.myOutputStream());
+        assertNull(dos.myMessageDigest());
+    }
+
+    /**
+     * @tests java.security.DigestOutputStream#getMessageDigest()
+     */
+    public void test_getMessageDigest() {
+
+        MessageDigest digest = new MyMessageDigest1();
+        OutputStream out = new MyOutputStream();
+
+        // non-null parameter
+        DigestOutputStream dos = new DigestOutputStream(out, digest);
+        assertSame(digest, dos.getMessageDigest());
+
+        // null parameter
+        dos = new DigestOutputStream(out, null);
+        assertNull("getMessageDigest should have returned null", dos
+                .getMessageDigest());
+    }
+
+    /**
+     * @tests java.security.DigestOutputStream#setMessageDigest(MessageDigest)
+     */
+    public void test_setMessageDigestLjava_security_MessageDigest() {
+
+        MessageDigest digest = new MyMessageDigest1();
+        OutputStream out = new MyOutputStream();
+
+        DigestOutputStream dos = new DigestOutputStream(out, null);
+
+        // non-null parameter
+        dos.setMessageDigest(digest);
+        assertSame(digest, dos.getMessageDigest());
+
+        // null parameter
+        dos.setMessageDigest(null);
+        assertNull("getMessageDigest should have returned null", dos
+                .getMessageDigest());
+    }
+
+
+    /**
+     * Test #1 for <code>write(int)</code> method<br>
+     * 
+     * Assertion: writes the byte to the output stream<br>
+     * Assertion: updates associated digest<br>
+     */
+    public final void testWriteint01()
+        throws IOException {
+        for (int k=0; k<algorithmName.length; k++) {
+            try {
+                MessageDigest md = MessageDigest.getInstance(algorithmName[k]);
+                ByteArrayOutputStream bos = new ByteArrayOutputStream(MY_MESSAGE_LEN);
+                DigestOutputStream dos = new DigestOutputStream(bos, md);
+                for (int i=0; i<MY_MESSAGE_LEN; i++) {
+                    dos.write(myMessage[i]);
+                }
+                // check that bytes have been written correctly
+                assertTrue("write", Arrays.equals(MDGoldenData.getMessage(),
+                        bos.toByteArray()));
+                // check that associated digest has been updated properly
+                assertTrue("update", Arrays.equals(dos.getMessageDigest().digest(),
+                        MDGoldenData.getDigest(algorithmName[k])));
+                return;
+            } catch (NoSuchAlgorithmException e) {
+                // allowed failure
+            }
+        }
+        fail(getName() + ": no MessageDigest algorithms available - test not performed");
+    }
+
+    /**
+     * Test #2 for <code>write(int)</code> method<br>
+     * Test #1 for <code>on(boolean)</code> method<br>
+     * 
+     * Assertion: <code>write(int)</code> must not update digest if it is off<br>
+     * Assertion: <code>on(boolean)</code> turns digest functionality on
+     * if <code>true</code> passed as a parameter or off if <code>false</code>
+     * passed
+     */
+    public final void testWriteint02()
+        throws IOException {
+        for (int k=0; k<algorithmName.length; k++) {
+            try {
+                MessageDigest md = MessageDigest.getInstance(algorithmName[k]);
+                ByteArrayOutputStream bos = new ByteArrayOutputStream(MY_MESSAGE_LEN);
+                DigestOutputStream dos = new DigestOutputStream(bos, md);
+                
+                // turn digest off
+                dos.on(false);
+                
+                for (int i=0; i<MY_MESSAGE_LEN; i++) {
+                    dos.write(myMessage[i]);
+                }
+                
+                // check that bytes have been written correctly
+                assertTrue("write", Arrays.equals(MDGoldenData.getMessage(),
+                        bos.toByteArray()));
+                // check that digest value has not been updated by write()
+                assertTrue("update", Arrays.equals(dos.getMessageDigest().digest(),
+                        MDGoldenData.getDigest(algorithmName[k]+"_NU")));
+                return;
+            } catch (NoSuchAlgorithmException e) {
+                // allowed failure
+            }
+        }
+        fail(getName() + ": no MessageDigest algorithms available - test not performed");
+    }
+
+    /**
+     * Test #3 for <code>write(int)</code> method<br>
+     * 
+     * Assertion: broken <code>DigestOutputStream</code>instance: 
+     * <code>OutputStream</code> not set. <code>write(int)</code> must
+     * not work
+     */
+    public final void testWriteint03() throws IOException {
+        for (int k=0; k<algorithmName.length; k++) {
+            try {
+                MessageDigest md = MessageDigest.getInstance(algorithmName[k]);
+                DigestOutputStream dos = new DigestOutputStream(null, md);
+                // must result in an exception
+                try {
+                    for (int i=0; i<MY_MESSAGE_LEN; i++) {
+                        dos.write(myMessage[i]);
+                    }
+                    fail("OutputStream not set. write(int) must not work");
+                } catch (Exception e) {
+                    return;
+                }
+            } catch (NoSuchAlgorithmException e) {
+                // allowed failure
+            }
+        }
+        fail(getName() + ": no MessageDigest algorithms available - test not performed");
+    }
+
+    /**
+     * Test #4 for <code>write(int)</code> method<br>
+     * 
+     * Assertion: broken <code>DigestOutputStream</code>instance: 
+     * associated <code>MessageDigest</code> not set.
+     * <code>write(int)</code> must not work when digest
+     * functionality is on
+     */
+    public final void testWriteint04() throws IOException {
+        OutputStream os = new ByteArrayOutputStream(MY_MESSAGE_LEN);
+        DigestOutputStream dos = new DigestOutputStream(os, null);
+
+        // must result in an exception
+        try {
+            for (int i=0; i<MY_MESSAGE_LEN; i++) {
+                dos.write(myMessage[i]);
+            }
+            fail("OutputStream not set. write(int) must not work");
+        } catch (Exception e) {
+            return;
+        }
+    }
+
+    /**
+     * Test #5 for <code>write(int)</code> method<br>
+     * Test #2 for <code>on(boolean)</code> method<br>
+     * 
+     * Assertion: broken <code>DigestOutputStream</code>instance: 
+     * associated <code>MessageDigest</code> not set.
+     * <code>write(int)</code> must work when digest
+     * functionality is off
+     */
+    public final void testWriteint05() throws IOException {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream(MY_MESSAGE_LEN);
+        DigestOutputStream dos = new DigestOutputStream(bos, null);
+        // set digest functionality to off
+        dos.on(false);
+        // the following must pass without any exception
+        for (int i=0; i<MY_MESSAGE_LEN; i++) {
+            dos.write(myMessage[i]);
+        }
+        // check that bytes have been written correctly
+        assertTrue(Arrays.equals(MDGoldenData.getMessage(),
+                bos.toByteArray()));
+    }
+
+    /**
+     * Test #1 for <code>write(byte[],int,int)</code> method<br>
+     * 
+     * Assertion: put bytes into output stream<br>
+     * 
+     * Assertion: updates associated digest<br>
+     */
+    public final void testWritebyteArrayintint01()
+        throws IOException {
+        for (int k=0; k<algorithmName.length; k++) {
+            try {
+                ByteArrayOutputStream bos = new ByteArrayOutputStream(MY_MESSAGE_LEN);
+                MessageDigest md = MessageDigest.getInstance(algorithmName[k]);
+                DigestOutputStream dos = new DigestOutputStream(bos, md);
+                
+                // write message at once
+                dos.write(myMessage, 0, MY_MESSAGE_LEN);
+                
+                // check write
+                assertTrue("write", Arrays.equals(myMessage, bos.toByteArray()));
+                // check that associated digest has been updated properly
+                assertTrue("update", Arrays.equals(dos.getMessageDigest().digest(),
+                        MDGoldenData.getDigest(algorithmName[k])));
+                return;
+            } catch (NoSuchAlgorithmException e) {
+                // allowed failure
+            }
+        }
+        fail(getName() + ": no MessageDigest algorithms available - test not performed");
+    }
+
+    /**
+     * Test #2 for <code>write(byte[],int,int)</code> method<br>
+     * 
+     * Assertion: put bytes into output stream<br>
+     * 
+     * Assertion: updates associated digest<br>
+     */
+    public final void testWritebyteArrayintint02()
+        throws IOException {
+        // check precondition
+        assertEquals(0, MY_MESSAGE_LEN % CHUNK_SIZE);
+        for (int k=0; k<algorithmName.length; k++) {
+            try {
+                
+                ByteArrayOutputStream bos = new ByteArrayOutputStream(MY_MESSAGE_LEN);
+                MessageDigest md = MessageDigest.getInstance(algorithmName[k]);
+                DigestOutputStream dos = new DigestOutputStream(bos, md);
+                
+                // write message by chunks
+                for (int i=0; i<MY_MESSAGE_LEN/CHUNK_SIZE; i++) {
+                    dos.write(myMessage, i*CHUNK_SIZE, CHUNK_SIZE);
+                }
+                // check write
+                assertTrue("write", Arrays.equals(myMessage, bos.toByteArray()));
+                // check that associated digest has been updated properly
+                assertTrue("update", Arrays.equals(dos.getMessageDigest().digest(),
+                        MDGoldenData.getDigest(algorithmName[k])));
+                return;
+            } catch (NoSuchAlgorithmException e) {
+                // allowed failure
+            }
+        }
+        fail(getName() + ": no MessageDigest algorithms available - test not performed");
+    }
+
+
+    /**
+     * Test #3 for <code>write(byte[],int,int)</code> method<br>
+     * 
+     * Assertion: put bytes into output stream<br>
+     * 
+     * Assertion: updates associated digest<br>
+     */
+    public final void testWritebyteArrayintint03()
+        throws NoSuchAlgorithmException,
+               IOException {
+        // check precondition
+        assertTrue(MY_MESSAGE_LEN % (CHUNK_SIZE+1) != 0);
+        
+        for (int k=0; k<algorithmName.length; k++) {
+            try {
+                ByteArrayOutputStream bos = new ByteArrayOutputStream(MY_MESSAGE_LEN);
+                MessageDigest md = MessageDigest.getInstance(algorithmName[k]);
+                DigestOutputStream dos = new DigestOutputStream(bos, md);
+                
+                // write message by chunks
+                for (int i=0; i<MY_MESSAGE_LEN/(CHUNK_SIZE+1); i++) {
+                    dos.write(myMessage, i*(CHUNK_SIZE+1), CHUNK_SIZE+1);
+                }
+                // write remaining bytes
+                dos.write(myMessage,
+                        MY_MESSAGE_LEN/(CHUNK_SIZE+1)*(CHUNK_SIZE+1),
+                        MY_MESSAGE_LEN % (CHUNK_SIZE+1));
+                // check write
+                assertTrue("write", Arrays.equals(myMessage, bos.toByteArray()));
+                // check that associated digest has been updated properly
+                assertTrue("update", Arrays.equals(dos.getMessageDigest().digest(),
+                        MDGoldenData.getDigest(algorithmName[k])));
+                return;
+            } catch (NoSuchAlgorithmException e) {
+                // allowed failure
+            }
+        }
+        fail(getName() + ": no MessageDigest algorithms available - test not performed");
+    }
+
+    /**
+     * Test #4 for <code>write(byte[],int,int)</code> method<br>
+     * 
+     * Assertion: put bytes into output stream<br>
+     * 
+     * Assertion: does not update associated digest if digest
+     * functionality is off<br>
+     */
+    public final void testWritebyteArrayintint04()
+        throws NoSuchAlgorithmException,
+               IOException {
+        // check precondition
+        assertEquals(0, MY_MESSAGE_LEN % CHUNK_SIZE);
+
+        for (int k=0; k<algorithmName.length; k++) {
+            try {
+                ByteArrayOutputStream bos = new ByteArrayOutputStream(MY_MESSAGE_LEN);
+                MessageDigest md = MessageDigest.getInstance(algorithmName[k]);
+                DigestOutputStream dos = new DigestOutputStream(bos, md);
+                
+                // set digest functionality off
+                dos.on(false);
+                
+                // write message by chunks
+                for (int i=0; i<MY_MESSAGE_LEN/CHUNK_SIZE; i++) {
+                    dos.write(myMessage, i*CHUNK_SIZE, CHUNK_SIZE);
+                }
+                
+                // check write
+                assertTrue("write", Arrays.equals(myMessage, bos.toByteArray()));
+                // check that associated digest has not been updated
+                assertTrue("update", Arrays.equals(dos.getMessageDigest().digest(),
+                        MDGoldenData.getDigest(algorithmName[k]+"_NU")));
+                return;
+            } catch (NoSuchAlgorithmException e) {
+                // allowed failure
+            }
+        }
+        fail(getName() + ": no MessageDigest algorithms available - test not performed");
+    }
+
+    /**
+     * @tests java.security.DigestOutputStream#write(byte[], int, int)
+     */
+    public void test_writeLB$LILI() throws Exception {
+
+        // Regression form HARMONY-1091.
+        MessageDigest md = new MyMessageDigest1();
+        byte[] bytes = new byte[] { 1, 2 };
+        DigestOutputStream dig = new DigestOutputStream(
+                new ByteArrayOutputStream(), md);
+        // buf == null
+        try {
+            dig.write(null, -1, 0);
+            fail("No expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+        }
+        // offset + len > buf.length
+        try {
+            dig.write(bytes, 0, bytes.length + 1);
+            fail("No expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+        }
+        // offset < 0
+        try {
+            dig.write(bytes, -1, 1);
+            fail("No expected IndexOutOfBoundsException");
+        } catch (IndexOutOfBoundsException e) {
+        }
+        // len < 0
+        try {
+            dig.write(bytes, 0, -1);
+            fail("No expected IndexOutOfBoundsException");
+        } catch (IndexOutOfBoundsException e) {
+        }
+    }
+
+    /**
+     * Test for <code>on()</code> method<br>
+     * Assertion: turns digest functionality on or off
+     */
+    public final void testOn() throws IOException {
+        for (int k=0; k<algorithmName.length; k++) {
+            try {
+                ByteArrayOutputStream bos = new ByteArrayOutputStream(MY_MESSAGE_LEN);
+                MessageDigest md = MessageDigest.getInstance(algorithmName[k]);
+                DigestOutputStream dos = new DigestOutputStream(bos, md);
+                
+                // turn digest off
+                dos.on(false);
+                
+                for (int i=0; i<MY_MESSAGE_LEN-1; i++) {
+                    dos.write(myMessage[i]);
+                }
+                
+                // turn digest on
+                dos.on(true);
+                
+                // read remaining byte
+                dos.write(myMessage[MY_MESSAGE_LEN-1]);
+                
+                byte[] digest = dos.getMessageDigest().digest();
+                
+                // check that digest value has been
+                // updated by the last write(int) call
+                assertFalse(
+                        Arrays.equals(digest,MDGoldenData.getDigest(algorithmName[k])) ||
+                        Arrays.equals(digest,MDGoldenData.getDigest(algorithmName[k]+"_NU")));
+                return;
+            } catch (NoSuchAlgorithmException e) {
+                // allowed failure
+            }
+        }
+        fail(getName() + ": no MessageDigest algorithms available - test not performed");
+    }
+
+    /**
+     * Test for <code>toString()</code> method<br>
+     * Assertion: returns <code>String</code> representation of this object
+     */
+    public final void testToString() throws NoSuchAlgorithmException {
+        for (int k=0; k<algorithmName.length; k++) {
+            try {
+                ByteArrayOutputStream bos = new ByteArrayOutputStream(MY_MESSAGE_LEN);
+                MessageDigest md = MessageDigest.getInstance(algorithmName[k]);
+                DigestOutputStream dos = new DigestOutputStream(bos, md);
+
+                assertNotNull(dos.toString());
+                return;
+            } catch (NoSuchAlgorithmException e) {
+                // allowed failure
+            }
+        }
+        fail(getName() + ": no MessageDigest algorithms available - test not performed");
+    }
+
+    /**
+     * @tests java.security.DigestOutputStream#on(boolean)
+     */
+    public void test_onZ() {
+        // Test for method void java.security.DigestOutputStream.on(boolean)
+        try {
+            DigestOutputStream dos = new DigestOutputStream(
+                    new ByteArrayOutputStream(), MessageDigest
+                            .getInstance("SHA"));
+            dos.on(false);
+            byte digestArray[] = { 23, 43, 44 };
+            dos.write(digestArray, 1, 1);
+            byte digestResult[] = dos.getMessageDigest().digest();
+            byte expected[] = { -38, 57, -93, -18, 94, 107, 75, 13, 50, 85,
+                    -65, -17, -107, 96, 24, -112, -81, -40, 7, 9 };
+            assertTrue("Digest did not return expected result.",
+                    java.util.Arrays.equals(digestResult, expected));
+            // now turn on processing and re-run
+            dos.on(true);
+            dos.write(digestArray, 1, 1);
+            digestResult = dos.getMessageDigest().digest();
+            byte expected1[] = { -87, 121, -17, 16, -52, 111, 106, 54, -33,
+                    107, -118, 50, 51, 7, -18, 59, -78, -30, -37, -100 };
+
+            assertTrue("Digest did not return expected result.",
+                    java.util.Arrays.equals(digestResult, expected1));
+        } catch (Exception e) {
+            fail("Caught exception : " + e);
+        }
+    }
+
+    /**
+     * @tests java.security.DigestOutputStream#write(byte[], int, int)
+     */
+    public void test_write$BII() throws Exception {
+        // Test for method void java.security.DigestOutputStream.write(byte [],
+        // int, int)
+            DigestOutputStream dos = new DigestOutputStream(
+                new ByteArrayOutputStream(), MessageDigest.getInstance("SHA"));
+            byte digestArray[] = { 23, 43, 44 };
+            dos.write(digestArray, 1, 1);
+            byte digestResult[] = dos.getMessageDigest().digest();
+            byte expected[] = { -87, 121, -17, 16, -52, 111, 106, 54, -33, 107,
+                    -118, 50, 51, 7, -18, 59, -78, -30, -37, -100 };
+
+            assertTrue("Digest did not return expected result.",
+                    java.util.Arrays.equals(digestResult, expected));
+    }
+
+    /**
+     * @tests java.security.DigestOutputStream#write(int)
+     */
+    public void test_writeI() throws Exception {
+        // Test for method void java.security.DigestOutputStream.write(int)
+            DigestOutputStream dos = new DigestOutputStream(
+                new ByteArrayOutputStream(), MessageDigest.getInstance("SHA"));
+            dos.write((byte) 43);
+            byte digestResult[] = dos.getMessageDigest().digest();
+            byte expected[] = { -87, 121, -17, 16, -52, 111, 106, 54, -33, 107,
+                    -118, 50, 51, 7, -18, 59, -78, -30, -37, -100 };
+
+            assertTrue("Digest did not return expected result.",
+                    java.util.Arrays.equals(digestResult, expected));
+    }
+
+
+    private class MyOutputStream extends OutputStream {
+        @Override
+        public void write(int arg0) throws IOException {
+        }
+    }
+    
+    private class MyDigestOutputStream extends DigestOutputStream {
+        public MyDigestOutputStream(OutputStream out, MessageDigest digest) {
+            super(out, digest);
+        }
+
+        public MessageDigest myMessageDigest() {
+            return digest;
+        }
+
+        public OutputStream myOutputStream() {
+            return out;
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/GeneralSecurityException2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/GeneralSecurityException2Test.java
new file mode 100644
index 0000000..0af27e9
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/GeneralSecurityException2Test.java
@@ -0,0 +1,48 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.GeneralSecurityException;
+
+public class GeneralSecurityException2Test extends junit.framework.TestCase {
+
+    /**
+     * @tests java.security.GeneralSecurityException#GeneralSecurityException()
+     */
+    public void test_Constructor() {
+        // Test for method java.security.GeneralSecurityException()
+        GeneralSecurityException e = new GeneralSecurityException();
+        assertNotNull("Constructor returned null instance", e);
+        assertEquals("Failed toString test for constructed instance", "java.security.GeneralSecurityException", e
+                .toString());
+    }
+
+    /**
+     * @tests java.security.GeneralSecurityException#GeneralSecurityException(java.lang.String)
+     */
+    public void test_ConstructorLjava_lang_String() {
+        // Test for method
+        // java.security.GeneralSecurityException(java.lang.String)
+        GeneralSecurityException e = new GeneralSecurityException(
+                "test message");
+        assertNotNull("Constructor returned null instance", e);
+        assertEquals("Failed toString test for constructed instance", 
+                        "java.security.GeneralSecurityException: test message", e
+                .toString());
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/GeneralSecurityExceptionTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/GeneralSecurityExceptionTest.java
new file mode 100644
index 0000000..01388e4
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/GeneralSecurityExceptionTest.java
@@ -0,0 +1,190 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.GeneralSecurityException;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>GeneralSecurityException</code> class constructors and
+ * methods.
+ * 
+ */
+public class GeneralSecurityExceptionTest extends TestCase {
+
+    public static void main(String[] args) {
+    }
+
+    /**
+     * Constructor for GeneralSecurityExceptionTests.
+     * 
+     * @param arg0
+     */
+    public GeneralSecurityExceptionTest(String arg0) {
+        super(arg0);
+    }
+
+    private static String[] msgs = {
+            "",
+            "Check new message",
+            "Check new message Check new message Check new message Check new message Check new message" };
+
+    private static Throwable tCause = new Throwable("Throwable for exception");
+
+    /**
+     * Test for <code>GeneralSecurityException()</code> constructor Assertion:
+     * constructs GeneralSecurityException with no detail message
+     */
+    public void testGeneralSecurityException01() {
+        GeneralSecurityException tE = new GeneralSecurityException();
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>GeneralSecurityException(String)</code> constructor
+     * Assertion: constructs GeneralSecurityException with detail message msg.
+     * Parameter <code>msg</code> is not null.
+     */
+    public void testGeneralSecurityException02() {
+        GeneralSecurityException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new GeneralSecurityException(msgs[i]);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+
+    /**
+     * Test for <code>GeneralSecurityException(String)</code> constructor
+     * Assertion: constructs GeneralSecurityException when <code>msg</code> is
+     * null
+     */
+    public void testGeneralSecurityException03() {
+        String msg = null;
+        GeneralSecurityException tE = new GeneralSecurityException(msg);
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>GeneralSecurityException(Throwable)</code> constructor
+     * Assertion: constructs GeneralSecurityException when <code>cause</code>
+     * is null
+     */
+    public void testGeneralSecurityException04() {
+        Throwable cause = null;
+        GeneralSecurityException tE = new GeneralSecurityException(cause);
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>GeneralSecurityException(Throwable)</code> constructor
+     * Assertion: constructs GeneralSecurityException when <code>cause</code>
+     * is not null
+     */
+    public void testGeneralSecurityException05() {
+        GeneralSecurityException tE = new GeneralSecurityException(tCause);
+        if (tE.getMessage() != null) {
+            String toS = tCause.toString();
+            String getM = tE.getMessage();
+            assertTrue("getMessage() should contain ".concat(toS), (getM
+                    .indexOf(toS) != -1));
+        }
+        assertNotNull("getCause() must not return null", tE.getCause());
+        assertEquals("getCause() must return ".concat(tCause.toString()), tE
+                .getCause(), tCause);
+    }
+
+    /**
+     * Test for <code>GeneralSecurityException(String, Throwable)</code>
+     * constructor Assertion: constructs GeneralSecurityException when
+     * <code>cause</code> is null <code>msg</code> is null
+     */
+    public void testGeneralSecurityException06() {
+        GeneralSecurityException tE = new GeneralSecurityException(null, null);
+        assertNull("getMessage() must return null", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>GeneralSecurityException(String, Throwable)</code>
+     * constructor Assertion: constructs GeneralSecurityException when
+     * <code>cause</code> is null <code>msg</code> is not null
+     */
+    public void testGeneralSecurityException07() {
+        GeneralSecurityException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new GeneralSecurityException(msgs[i], null);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+
+    /**
+     * Test for <code>GeneralSecurityException(String, Throwable)</code>
+     * constructor Assertion: constructs GeneralSecurityException when
+     * <code>cause</code> is not null <code>msg</code> is null
+     */
+    public void testGeneralSecurityException08() {
+        GeneralSecurityException tE = new GeneralSecurityException(null, tCause);
+        if (tE.getMessage() != null) {
+            String toS = tCause.toString();
+            String getM = tE.getMessage();
+            assertTrue("getMessage() must should ".concat(toS), (getM
+                    .indexOf(toS) != -1));
+        }
+        assertNotNull("getCause() must not return null", tE.getCause());
+        assertEquals("getCause() must return ".concat(tCause.toString()), tE
+                .getCause(), tCause);
+    }
+
+    /**
+     * Test for <code>GeneralSecurityException(String, Throwable)</code>
+     * constructor Assertion: constructs GeneralSecurityException when
+     * <code>cause</code> is not null <code>msg</code> is not null
+     */
+    public void testGeneralSecurityException09() {
+        GeneralSecurityException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new GeneralSecurityException(msgs[i], tCause);
+            String getM = tE.getMessage();
+            String toS = tCause.toString();
+            if (msgs[i].length() > 0) {
+                assertTrue("getMessage() must contain ".concat(msgs[i]), getM
+                        .indexOf(msgs[i]) != -1);
+                if (!getM.equals(msgs[i])) {
+                    assertTrue("getMessage() should contain ".concat(toS), getM
+                            .indexOf(toS) != -1);
+                }
+            }
+            assertNotNull("getCause() must not return null", tE.getCause());
+            assertEquals("getCause() must return ".concat(tCause.toString()),
+                    tE.getCause(), tCause);
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/GuardedObjectTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/GuardedObjectTest.java
new file mode 100644
index 0000000..0070519
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/GuardedObjectTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.Guard;
+import java.security.GuardedObject;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>GuardedObject</code>
+ * 
+ */
+
+public class GuardedObjectTest extends TestCase {
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(GuardedObjectTest.class);
+    }
+
+    /** Null guard imposes no restriction. */
+    public void testNoGuard() {
+        Object obj = null;
+        GuardedObject go = new GuardedObject(obj, null);
+        assertNull(go.getObject());
+
+        obj = "ewte rtw3456";
+        go = new GuardedObject(obj, null);
+        assertEquals(obj, go.getObject());
+    }
+
+    /** Test real guard can both allow and deny access. */
+    public void testGuard() {
+        final String message = "test message";
+        final StringBuffer objBuffer = new StringBuffer("235345 t");
+        GuardedObject go = new GuardedObject(objBuffer, new Guard() {
+
+            public void checkGuard(Object object) throws SecurityException {
+                if (object == objBuffer && objBuffer.length() == 0) {
+                    throw new SecurityException(message);
+                }
+            }
+        });
+        assertEquals(objBuffer, go.getObject());
+
+        objBuffer.setLength(0);
+        try {
+            go.getObject();
+            fail("SecurityException is not thrown");
+        } catch (Exception ok) {
+            assertEquals(message, ok.getMessage());
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/Identity2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/Identity2Test.java
new file mode 100644
index 0000000..d20cdfa
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/Identity2Test.java
@@ -0,0 +1,341 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.Identity;
+import java.security.IdentityScope;
+import java.security.KeyManagementException;
+import java.security.KeyPairGenerator;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import org.apache.harmony.security.tests.java.security.IdentityScope2Test.IdentityScopeSubclass;;
+
+@SuppressWarnings("deprecation")
+
+public class Identity2Test extends junit.framework.TestCase {
+
+    static PublicKey pubKey;
+    static {
+        try {
+            pubKey = KeyPairGenerator.getInstance("DSA").genKeyPair().getPublic();
+        } catch (Exception e) {
+            fail(e.toString());
+        }
+    }
+     
+    
+    public static class CertificateImpl implements java.security.Certificate {
+
+        X509Certificate cert;
+
+        public CertificateImpl(X509Certificate cert) {
+            this.cert = cert;
+        }
+
+        public Principal getGuarantor() {
+            return cert.getIssuerDN();
+        }
+
+        public void encode(OutputStream out) {
+        }
+
+        public void decode(InputStream in) {
+        }
+
+        public String toString() {
+            return "";
+        }
+
+        public String toString(boolean b) {
+            return "";
+        }
+
+        public String getFormat() {
+            return cert.getType();
+        }
+
+        public Principal getPrincipal() {
+            return cert.getSubjectDN();
+        }
+
+        public PublicKey getPublicKey() {
+            return cert.getPublicKey();
+        }
+    }
+
+    String certificate = "-----BEGIN CERTIFICATE-----\n"
+            + "MIICZTCCAdICBQL3AAC2MA0GCSqGSIb3DQEBAgUAMF8xCzAJBgNVBAYTAlVTMSAw\n"
+            + "HgYDVQQKExdSU0EgRGF0YSBTZWN1cml0eSwgSW5jLjEuMCwGA1UECxMlU2VjdXJl\n"
+            + "IFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05NzAyMjAwMDAwMDBa\n"
+            + "Fw05ODAyMjAyMzU5NTlaMIGWMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZv\n"
+            + "cm5pYTESMBAGA1UEBxMJUGFsbyBBbHRvMR8wHQYDVQQKExZTdW4gTWljcm9zeXN0\n"
+            + "ZW1zLCBJbmMuMSEwHwYDVQQLExhUZXN0IGFuZCBFdmFsdWF0aW9uIE9ubHkxGjAY\n"
+            + "BgNVBAMTEWFyZ29uLmVuZy5zdW4uY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB\n"
+            + "iQKBgQCofmdY+PiUWN01FOzEewf+GaG+lFf132UpzATmYJkA4AEA/juW7jSi+LJk\n"
+            + "wJKi5GO4RyZoyimAL/5yIWDV6l1KlvxyKslr0REhMBaD/3Z3EsLTTEf5gVrQS6sT\n"
+            + "WMoSZAyzB39kFfsB6oUXNtV8+UKKxSxKbxvhQn267PeCz5VX2QIDAQABMA0GCSqG\n"
+            + "SIb3DQEBAgUAA34AXl3at6luiV/7I9MN5CXYoPJYI8Bcdc1hBagJvTMcmlqL2uOZ\n"
+            + "H9T5hNMEL9Tk6aI7yZPXcw/xI2K6pOR/FrMp0UwJmdxX7ljV6ZtUZf7pY492UqwC\n"
+            + "1777XQ9UEZyrKJvF5ntleeO0ayBqLGVKCWzWZX9YsXCpv47FNLZbupE=\n"
+            + "-----END CERTIFICATE-----\n";
+
+    ByteArrayInputStream certArray = new ByteArrayInputStream(certificate
+            .getBytes());
+
+    String certificate2 = "-----BEGIN CERTIFICATE-----\n"
+            + "MIICZzCCAdCgAwIBAgIBGzANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJVUzEY\n"
+            + "MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT\n"
+            + "A1BLSTEcMBoGA1UEAxMTRG9EIFBLSSBNZWQgUm9vdCBDQTAeFw05ODA4MDMyMjAy\n"
+            + "MjlaFw0wODA4MDQyMjAyMjlaMGExCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMu\n"
+            + "IEdvdmVybm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRwwGgYDVQQD\n"
+            + "ExNEb0QgUEtJIE1lZCBSb290IENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n"
+            + "gQDbrM/J9FrJSX+zxFUbsI9Vw5QbguVBIa95rwW/0M8+sM0r5gd+DY6iubm6wnXk\n"
+            + "CSvbfQlFEDSKr4WYeeGp+d9WlDnQdtDFLdA45tCi5SHjnW+hGAmZnld0rz6wQekF\n"
+            + "5xQaa5A6wjhMlLOjbh27zyscrorMJ1O5FBOWnEHcRv6xqQIDAQABoy8wLTAdBgNV\n"
+            + "HQ4EFgQUVrmYR6m9701cHQ3r5kXyG7zsCN0wDAYDVR0TBAUwAwEB/zANBgkqhkiG\n"
+            + "9w0BAQUFAAOBgQDVX1Y0YqC7vekeZjVxtyuC8Mnxbrz6D109AX07LEIRzNYzwZ0w\n"
+            + "MTImSp9sEzWW+3FueBIU7AxGys2O7X0qmN3zgszPfSiocBuQuXIYQctJhKjF5KVc\n"
+            + "VGQRYYlt+myhl2vy6yPzEVCjiKwMEb1Spu0irCf+lFW2hsdjvmSQMtZvOw==\n"
+            + "-----END CERTIFICATE-----\n";
+
+    ByteArrayInputStream certArray2 = new ByteArrayInputStream(certificate2
+            .getBytes());
+
+    
+    public static class IdentitySubclass extends Identity {
+        public IdentitySubclass() {
+            super();
+        }
+
+        public IdentitySubclass(String name) {
+            super(name);
+        }
+
+        public IdentitySubclass(String name, IdentityScope scope)
+                throws KeyManagementException {
+            super(name, scope);
+        }
+    }
+
+    /**
+     * @tests java.security.Identity#Identity()
+     */
+    public void test_Constructor() {
+        new IdentitySubclass();
+    }
+
+    /**
+     * @tests java.security.Identity#Identity(java.lang.String)
+     */
+    public void test_ConstructorLjava_lang_String() {
+        new IdentitySubclass("test");
+    }
+
+    /**
+     * @tests java.security.Identity#Identity(java.lang.String,
+     *        java.security.IdentityScope)
+     */
+    
+    public void test_ConstructorLjava_lang_StringLjava_security_IdentityScope() throws Exception {
+               new IdentitySubclass("test", new IdentityScopeSubclass());
+    }
+
+    /**
+     * @tests java.security.Identity#getScope()
+     */
+    public void test_getScope() throws Exception {
+               IdentityScope scope = new IdentityScopeSubclass();
+               IdentitySubclass sub = new IdentitySubclass("test", scope);
+               IdentityScope returnedScope = sub.getScope();
+               assertEquals("Wrong Scope returned", scope, returnedScope);
+    }
+
+    /**
+     * @tests java.security.Identity#getPublicKey()
+     */
+    public void test_getPublicKey() throws Exception {
+               IdentitySubclass sub = new IdentitySubclass("test",
+                       new IdentityScopeSubclass());
+               sub.setPublicKey(pubKey);
+               PublicKey returnedPubKey = sub.getPublicKey();
+               assertEquals("Wrong PublicKey returned", pubKey, returnedPubKey);
+    }
+
+    /**
+     * @tests java.security.Identity#getName()
+     */
+    public void test_getName() throws Exception {
+               String name = "test";
+               IdentitySubclass sub = new IdentitySubclass(name,
+                       new IdentityScopeSubclass());
+               assertEquals("Wrong Name returned", name, sub.getName());
+    }
+
+    /**
+     * @tests java.security.Identity#getInfo()
+     */
+    public void test_getInfo() throws Exception {
+               String info = "This is the general information.";
+               IdentitySubclass sub = new IdentitySubclass("test",
+                       new IdentityScopeSubclass());
+               sub.setInfo(info);
+               assertEquals("Wrong Info returned", info, sub.getInfo());
+    }
+
+    /**
+     * @tests java.security.Identity#certificates()
+     */
+    public void test_certificates() throws Exception {
+               IdentitySubclass sub = new IdentitySubclass("test",
+                       new IdentityScopeSubclass());
+               CertificateFactory cf = CertificateFactory.getInstance("X.509");
+               X509Certificate cert[] = new X509Certificate[1];
+               cert[0] = (X509Certificate) cf.generateCertificate(certArray);
+               sub.setPublicKey(cert[0].getPublicKey());
+               CertificateImpl certImpl = new CertificateImpl(cert[0]);
+               sub.addCertificate(certImpl);
+               java.security.Certificate[] certs = sub.certificates();
+               assertEquals("Certificate not contained in the identity",
+                       certs[0], certImpl);
+    }
+
+    /**
+     * @tests java.security.Identity#addCertificate(java.security.Certificate)
+     */
+    public void test_addCertificateLjava_security_Certificate() throws Exception {
+               IdentitySubclass sub = new IdentitySubclass("test",
+                       new IdentityScopeSubclass());
+               CertificateFactory cf = CertificateFactory.getInstance("X.509");
+               X509Certificate cert[] = new X509Certificate[1];
+               cert[0] = (X509Certificate) cf.generateCertificate(certArray);
+               sub.setPublicKey(cert[0].getPublicKey());
+               CertificateImpl certImpl = new CertificateImpl(cert[0]);
+               sub.addCertificate(certImpl);
+    }
+
+    /**
+     * @tests java.security.Identity#removeCertificate(java.security.Certificate)
+     */
+    public void test_removeCertificateLjava_security_Certificate() throws Exception {
+               IdentitySubclass sub = new IdentitySubclass("test",
+                       new IdentityScopeSubclass());
+               CertificateFactory cf = CertificateFactory.getInstance("X.509");
+               X509Certificate cert[] = new X509Certificate[1];
+               cert[0] = (X509Certificate) cf.generateCertificate(certArray);
+               sub.setPublicKey(cert[0].getPublicKey());
+               CertificateImpl certImpl = new CertificateImpl(cert[0]);
+               sub.addCertificate(certImpl);
+               sub.removeCertificate(certImpl);
+               java.security.Certificate[] certs = sub.certificates();
+               assertEquals("Certificate not removed", 0, certs.length);
+    }
+
+    /**
+     * @tests java.security.Identity#equals(java.lang.Object)
+     */
+    public void test_equalsLjava_lang_Object() throws Exception {
+               IdentitySubclass sub = new IdentitySubclass("test",
+                       new IdentityScopeSubclass());
+               CertificateFactory cf = CertificateFactory.getInstance("X.509");
+               X509Certificate cert[] = new X509Certificate[1];
+               cert[0] = (X509Certificate) cf.generateCertificate(certArray);
+               sub.setPublicKey(cert[0].getPublicKey());
+               CertificateImpl certImpl = new CertificateImpl(cert[0]);
+               sub.addCertificate(certImpl);
+               IdentitySubclass sub2 = new IdentitySubclass("test",
+                       new IdentityScopeSubclass());
+               assertEquals("the two Identity objects are not equal", sub2, sub);
+    }
+
+    /**
+     * @tests java.security.Identity#identityEquals(java.security.Identity)
+     */
+    public void test_identityEqualsLjava_security_Identity() throws Exception {
+               IdentitySubclass sub = new IdentitySubclass("test", null);
+               CertificateFactory cf = CertificateFactory.getInstance("X.509");
+               X509Certificate cert[] = new X509Certificate[1];
+               cert[0] = (X509Certificate) cf.generateCertificate(certArray);
+               sub.setPublicKey(cert[0].getPublicKey());
+               CertificateImpl certImpl = new CertificateImpl(cert[0]);
+               sub.addCertificate(certImpl);
+               IdentitySubclass sub2 = new IdentitySubclass("test", null);
+               sub2.setPublicKey(cert[0].getPublicKey());
+               assertEquals("the two Identity objects are not identity-equal",
+                       sub2, sub);
+    }
+
+    /**
+     * @tests java.security.Identity#toString()
+     */
+    public void test_toString() throws Exception {
+               IdentitySubclass sub = new IdentitySubclass("test", null);
+               assertNotNull(sub.toString());
+               assertTrue("The String returned is not valid", sub.toString()
+                       .length() > 0);
+               // Regression for HARMONY-1566
+               assertNotNull(new IdentitySubclass().toString());
+    }
+
+    /**
+     * @tests java.security.Identity#toString(boolean)
+     */
+    public void test_toStringZ() throws Exception {
+               IdentitySubclass sub = new IdentitySubclass("test", null);
+               assertNotNull(sub.toString(true));
+               assertTrue("The String returned is not valid", sub.toString(true)
+                       .length() > 0);
+    }
+
+    /**
+     * @tests java.security.Identity#hashCode()
+     */
+    public void test_hashCode() throws Exception {
+               IdentitySubclass sub = new IdentitySubclass("test", null);
+               IdentitySubclass sub2 = new IdentitySubclass("test", null);
+               assertEquals("The 2 hash codes are not equal", sub.hashCode(), sub2
+                       .hashCode());
+    }
+    
+    /**
+     * @tests java.security.Identity#setInfo(String)
+     */
+    public void testSetInfo() throws Exception{
+        String info = "This is the general information.";
+           IdentitySubclass sub = new IdentitySubclass("test",
+                   new IdentityScopeSubclass());
+           sub.setInfo(info);
+           assertEquals("Wrong Info returned", info, sub.getInfo());
+    }
+    
+    /**
+     * @tests java.security.Identity#hashCode()
+     */
+    public void testSetPublicKey() throws Exception{
+        IdentitySubclass sub = new IdentitySubclass("test",
+                   new IdentityScopeSubclass());
+           sub.setPublicKey(pubKey);
+           PublicKey returnedPubKey = sub.getPublicKey();
+           assertEquals("Wrong PublicKey returned", pubKey, returnedPubKey);
+    }
+
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/IdentityScope2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/IdentityScope2Test.java
new file mode 100644
index 0000000..e8bf437
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/IdentityScope2Test.java
@@ -0,0 +1,264 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.Identity;
+import java.security.IdentityScope;
+import java.security.KeyManagementException;
+import java.security.KeyPairGenerator;
+import java.security.PublicKey;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.apache.harmony.security.tests.java.security.Identity2Test.IdentitySubclass;
+@SuppressWarnings("deprecation")
+public class IdentityScope2Test extends junit.framework.TestCase {
+
+    static PublicKey pubKey;
+    static {
+        try {
+            pubKey = KeyPairGenerator.getInstance("DSA").genKeyPair().getPublic();
+        } catch (Exception e) {
+            fail(e.toString());
+        }
+    }
+
+    public static class IdentityScopeSubclass extends IdentityScope {
+        Hashtable<Identity, Identity> identities;
+
+        public IdentityScopeSubclass(String name, PublicKey pk) {
+            super(name);
+            try {
+                setPublicKey(pk);
+            } catch (KeyManagementException e) {
+            }
+            identities = new Hashtable<Identity, Identity>();
+        }
+
+        public IdentityScopeSubclass() {
+            super();
+            identities = new Hashtable<Identity, Identity>();
+        }
+
+        public IdentityScopeSubclass(String name) {
+            super(name);
+            identities = new Hashtable<Identity, Identity>();
+        }
+
+        public IdentityScopeSubclass(String name, IdentityScope scope)
+                throws KeyManagementException {
+            super(name, scope);
+            identities = new Hashtable<Identity, Identity>();
+        }
+
+        public int size() {
+            return identities.size();
+        }
+
+        public Identity getIdentity(String name) {
+            Enumeration en = identities();
+            while (en.hasMoreElements()) {
+                Identity current = (Identity) en.nextElement();
+                if (current.getName().equals(name))
+                    return current;
+            }
+            return null;
+        }
+
+        public Identity getIdentity(PublicKey pk) {
+            Enumeration en = identities();
+            while (en.hasMoreElements()) {
+                Identity current = (Identity) en.nextElement();
+                if (current.getPublicKey() == pk)
+                    return current;
+            }
+            return null;
+        }
+
+        public Enumeration<Identity> identities() {
+            return identities.elements();
+        }
+
+        public void addIdentity(Identity id) throws KeyManagementException {
+            if (identities.containsKey(id))
+                throw new KeyManagementException(
+                        "This Identity is already contained in the scope");
+            if (getIdentity(id.getPublicKey()) != null)
+                throw new KeyManagementException(
+                        "This Identity's public key already exists in the scope");
+            identities.put(id, id);
+        }
+
+        public void removeIdentity(Identity id) throws KeyManagementException {
+            if (!identities.containsKey(id))
+                throw new KeyManagementException(
+                        "This Identity is not contained in the scope");
+            identities.remove(id);
+        }
+    }
+
+    /**
+     * @tests java.security.IdentityScope#IdentityScope()
+     */
+    public void test_Constructor() {
+        new IdentityScopeSubclass();
+    }
+
+    /**
+     * @tests java.security.IdentityScope#IdentityScope(java.lang.String)
+     */
+    public void test_ConstructorLjava_lang_String() {
+        new IdentityScopeSubclass("test");
+    }
+
+    /**
+     * @tests java.security.IdentityScope#IdentityScope(java.lang.String,
+     *        java.security.IdentityScope)
+     */
+    public void test_ConstructorLjava_lang_StringLjava_security_IdentityScope() throws Exception {
+        new IdentityScopeSubclass("test", new IdentityScopeSubclass());
+    }
+
+    /**
+     * @tests java.security.IdentityScope#addIdentity(java.security.Identity)
+     */
+    public void test_addIdentityLjava_security_Identity() throws Exception {
+               IdentityScopeSubclass sub = new IdentityScopeSubclass("test",
+                       new IdentityScopeSubclass());
+               Identity id = new IdentitySubclass("id1");
+               id.setPublicKey(pubKey);
+               sub.addIdentity(id);
+               try {
+                   Identity id2 = new IdentitySubclass("id2");
+                   id2.setPublicKey(pubKey);
+                   sub.addIdentity(id2);
+                   fail("KeyManagementException should have been thrown");
+               } catch (KeyManagementException e) {
+                   // Expected
+               }
+    }
+
+    /**
+     * @tests java.security.IdentityScope#removeIdentity(java.security.Identity)
+     */
+    public void test_removeIdentityLjava_security_Identity() throws Exception {
+               IdentityScopeSubclass sub = new IdentityScopeSubclass("test",
+                       new IdentityScopeSubclass());
+               Identity id = new IdentitySubclass();
+               id.setPublicKey(pubKey);
+               sub.addIdentity(id);
+               sub.removeIdentity(id);
+               try {
+                   sub.removeIdentity(id);
+                   fail("KeyManagementException should have been thrown");
+               } catch (KeyManagementException e) {
+                   // expected
+               }
+    }
+
+    /**
+     * @tests java.security.IdentityScope#identities()
+     */
+    public void test_identities() throws Exception {
+               IdentityScopeSubclass sub = new IdentityScopeSubclass("test",
+                       new IdentityScopeSubclass());
+               Identity id = new IdentitySubclass();
+               id.setPublicKey(pubKey);
+               sub.addIdentity(id);
+               Enumeration en = sub.identities();
+               assertTrue("Wrong object contained in identities", en.nextElement()
+                       .equals(id));
+               assertTrue("Contains too many elements", !en.hasMoreElements());
+    }
+
+    /**
+     * @tests java.security.IdentityScope#getIdentity(java.security.Principal)
+     */
+    public void test_getIdentityLjava_security_Principal() throws Exception {
+               Identity id = new IdentitySubclass("principal name");
+               id.setPublicKey(pubKey);
+               IdentityScopeSubclass sub = new IdentityScopeSubclass("test",
+                       new IdentityScopeSubclass());
+               sub.addIdentity(id);
+               Identity returnedId = sub.getIdentity(id);
+               assertEquals("Returned Identity not the same as the added one", id,
+                       returnedId);
+    }
+
+    /**
+     * @tests java.security.IdentityScope#getIdentity(java.security.PublicKey)
+     */
+    public void test_getIdentityLjava_security_PublicKey() throws Exception {
+               IdentityScopeSubclass sub = new IdentityScopeSubclass("test",
+                       new IdentityScopeSubclass());
+               Identity id = new IdentitySubclass();
+               id.setPublicKey(pubKey);
+               sub.addIdentity(id);
+               Identity returnedId = sub.getIdentity(pubKey);
+               assertEquals("Returned Identity not the same as the added one", id,
+                       returnedId);
+    }
+
+    /**
+     * @tests java.security.IdentityScope#getIdentity(java.lang.String)
+     */
+    public void test_getIdentityLjava_lang_String() throws Exception {
+               IdentityScopeSubclass sub = new IdentityScopeSubclass("test",
+                       new IdentityScopeSubclass());
+               Identity id = new IdentitySubclass("test");
+               id.setPublicKey(pubKey);
+               sub.addIdentity(id);
+               Identity returnedId = sub.getIdentity("test");
+               assertEquals("Returned Identity not the same as the added one", id,
+                       returnedId);
+    }
+
+    /**
+     * @tests java.security.IdentityScope#size()
+     */
+    public void test_size() throws Exception {
+               IdentityScopeSubclass sub = new IdentityScopeSubclass("test",
+                       new IdentityScopeSubclass());
+               Identity id = new IdentitySubclass();
+               id.setPublicKey(pubKey);
+               sub.addIdentity(id);
+               assertEquals("Wrong size", 1, sub.size());
+    }
+
+    /**
+     * @tests java.security.IdentityScope#toString()
+     */
+    public void test_toString() throws Exception {
+            IdentityScopeSubclass sub = new IdentityScopeSubclass("test",
+                    new IdentityScopeSubclass());
+            Identity id = new IdentitySubclass();
+            id.setPublicKey(pubKey);
+            sub.addIdentity(id);
+            assertNotNull("toString returned a null", sub.toString());
+            assertTrue("Not a valid String ", sub.toString().length() > 0);
+    }
+
+    public void test_getIdentity() throws Exception {
+        //Regression for HARMONY-1173
+        IdentityScope scope = IdentityScope.getSystemScope(); 
+        try {
+            scope.getIdentity((String) null);
+            fail("NPE expected");
+        } catch (NullPointerException npe) {}
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/IdentityScopeTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/IdentityScopeTest.java
new file mode 100644
index 0000000..96387ca
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/IdentityScopeTest.java
@@ -0,0 +1,158 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Aleksei Y. Semenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.IdentityScope;
+import java.security.Permission;
+import java.security.Permissions;
+import java.security.Security;
+import java.security.SecurityPermission;
+
+import org.apache.harmony.security.tests.support.IdentityScopeStub;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>IdentityScope</code>
+ * 
+ */
+@SuppressWarnings("deprecation")
+public class IdentityScopeTest extends TestCase {
+
+    public static class MySecurityManager extends SecurityManager {
+        public Permissions denied = new Permissions(); 
+        public void checkPermission(Permission permission){
+            if (denied!=null && denied.implies(permission)) throw new SecurityException();
+        }
+    }
+    
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(IdentityScopeTest.class);
+    }
+    
+    IdentityScope is;
+
+    /**
+     * Constructor for IdentityScopeTest.
+     * @param arg0
+     */
+    public IdentityScopeTest(String arg0) {
+        super(arg0);
+    }
+
+    /**
+     * Class under test for String toString()
+     */
+    public final void testToString() {
+        assertNotNull(new IdentityScopeStub("Aleksei Semenov").toString());
+    }
+
+    /**
+     * test default constructor void IdentityScope()
+     */
+    public final void testIdentityScope() {
+        assertNotNull(new IdentityScopeStub());
+    }
+
+    /**
+     * check that void IdentityScope(String) creates instance with given name
+     */
+    public final void testIdentityScopeString() {
+        is = new IdentityScopeStub("Aleksei Semenov");
+        assertNotNull(is);
+        assertEquals("Aleksei Semenov", is.getName());
+    }
+
+    /**
+     * check that void IdentityScope(String, IdentityScope) creates instance with given name and within given scope
+     */
+    public final void testIdentityScopeStringIdentityScope() throws Exception {
+        IdentityScope scope = new IdentityScopeStub("my scope");
+        is = new IdentityScopeStub("Aleksei Semenov", scope);
+        assertNotNull(is);
+        assertEquals("Aleksei Semenov", is.getName());
+        assertEquals(scope.getName(), is.getScope().getName());
+    }
+
+    /**
+     * just call IdentityScope.getSystemScope()
+     */
+    public final void testGetSystemScope() {
+        String name = Security.getProperty("system.scope");
+        assertNotNull(name);
+        IdentityScope scope = IdentityScope.getSystemScope(); 
+        assertNotNull(scope);
+        assertEquals(name, scope.getClass().getName());
+    }
+
+    /**
+     * check that if permission given - set/get works
+     * if permission is denied than SecurityException is thrown
+     *
+     */
+    
+    public final void testSetSystemScope() {
+//      default implementation is specified by security property system.scope
+        IdentityScope systemScope = IdentityScope.getSystemScope();
+        
+        try {
+            // all permissions are granted - sm is not installed
+            is = new IdentityScopeStub("Aleksei Semenov");
+            IdentityScopeStub.mySetSystemScope(is);
+            assertSame(is, IdentityScope.getSystemScope());
+            // all permissions are granted - sm is installed
+            MySecurityManager sm = new MySecurityManager();
+            System.setSecurityManager(sm);
+            try {
+                is = new IdentityScopeStub("aaa");
+                IdentityScopeStub.mySetSystemScope(is);
+                assertSame(is, IdentityScope.getSystemScope());       
+                // permission is denied
+                sm.denied.add(new SecurityPermission("setSystemScope"));
+                IdentityScope is2 = new IdentityScopeStub("bbb");
+                try{
+                    IdentityScopeStub.mySetSystemScope(is2); 
+                    fail("SecurityException should be thrown");
+                } catch (SecurityException e){
+                    assertSame(is, IdentityScope.getSystemScope());
+                }
+            } finally {
+                System.setSecurityManager(null);
+                assertNull("Error, security manager is not removed!", System.getSecurityManager());
+            }
+        } finally {
+            IdentityScopeStub.mySetSystemScope(systemScope);
+        }
+    }
+    
+
+    /**
+     * Class under test for Identity getIdentity(Principal)
+     */
+    public final void testGetIdentityPrincipal() {
+        is = new IdentityScopeStub("Aleksei Semenov");
+        IdentityScope sc2 = new IdentityScopeStub("aaa");
+        assertSame(is, is.getIdentity(sc2));
+    }
+
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/InvalidAlgorithmParameterException2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/InvalidAlgorithmParameterException2Test.java
new file mode 100644
index 0000000..f648de0
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/InvalidAlgorithmParameterException2Test.java
@@ -0,0 +1,51 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.InvalidAlgorithmParameterException;
+
+public class InvalidAlgorithmParameterException2Test extends
+        junit.framework.TestCase {
+
+    /**
+     * @tests java.security.InvalidAlgorithmParameterException#InvalidAlgorithmParameterException()
+     */
+    public void test_Constructor() {
+        // Test for method java.security.InvalidAlgorithmParameterException()
+        InvalidAlgorithmParameterException e = new InvalidAlgorithmParameterException();
+        assertNotNull("Constructor returned null instance", e);
+        assertEquals("Failed toString test for constructed instance",
+                "java.security.InvalidAlgorithmParameterException", e
+                        .toString());
+    }
+
+    /**
+     * @tests java.security.InvalidAlgorithmParameterException#InvalidAlgorithmParameterException(java.lang.String)
+     */
+    public void test_ConstructorLjava_lang_String() {
+        // Test for method
+        // java.security.InvalidAlgorithmParameterException(java.lang.String)
+        InvalidAlgorithmParameterException e = new InvalidAlgorithmParameterException(
+                "test message");
+        assertNotNull("Constructor returned null instance", e);
+        assertEquals(
+                "Failed toString test for constructed instance",
+                "java.security.InvalidAlgorithmParameterException: test message",
+                e.toString());
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/InvalidAlgorithmParameterExceptionTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/InvalidAlgorithmParameterExceptionTest.java
new file mode 100644
index 0000000..802b940
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/InvalidAlgorithmParameterExceptionTest.java
@@ -0,0 +1,201 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.InvalidAlgorithmParameterException;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>InvalidAlgorithmParameterException</code> class
+ * constructors and methods.
+ * 
+ */
+public class InvalidAlgorithmParameterExceptionTest extends TestCase {
+
+    public static void main(String[] args) {
+    }
+
+    /**
+     * Constructor for InvalidAlgorithmParameterExceptionTests.
+     * 
+     * @param arg0
+     */
+    public InvalidAlgorithmParameterExceptionTest(String arg0) {
+        super(arg0);
+    }
+
+    private static String[] msgs = {
+            "",
+            "Check new message",
+            "Check new message Check new message Check new message Check new message Check new message" };
+
+    private static Throwable tCause = new Throwable("Throwable for exception");
+
+    /**
+     * Test for <code>InvalidAlgorithmParameterException()</code> constructor
+     * Assertion: constructs InvalidAlgorithmParameterException with no detail
+     * message
+     */
+    public void testInvalidAlgorithmParameterException01() {
+        InvalidAlgorithmParameterException tE = new InvalidAlgorithmParameterException();
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>InvalidAlgorithmParameterException(String)</code>
+     * constructor Assertion: constructs InvalidAlgorithmParameterException with
+     * detail message msg. Parameter <code>msg</code> is not null.
+     */
+    public void testInvalidAlgorithmParameterException02() {
+        InvalidAlgorithmParameterException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new InvalidAlgorithmParameterException(msgs[i]);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+
+    /**
+     * Test for <code>InvalidAlgorithmParameterException(String)</code>
+     * constructor Assertion: constructs InvalidAlgorithmParameterException when
+     * <code>msg</code> is null
+     */
+    public void testInvalidAlgorithmParameterException03() {
+        String msg = null;
+        InvalidAlgorithmParameterException tE = new InvalidAlgorithmParameterException(
+                msg);
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>InvalidAlgorithmParameterException(Throwable)</code>
+     * constructor Assertion: constructs InvalidAlgorithmParameterException when
+     * <code>cause</code> is null
+     */
+    public void testInvalidAlgorithmParameterException04() {
+        Throwable cause = null;
+        InvalidAlgorithmParameterException tE = new InvalidAlgorithmParameterException(
+                cause);
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>InvalidAlgorithmParameterException(Throwable)</code>
+     * constructor Assertion: constructs InvalidAlgorithmParameterException when
+     * <code>cause</code> is not null
+     */
+    public void testInvalidAlgorithmParameterException05() {
+        InvalidAlgorithmParameterException tE = new InvalidAlgorithmParameterException(
+                tCause);
+        if (tE.getMessage() != null) {
+            String toS = tCause.toString();
+            String getM = tE.getMessage();
+            assertTrue("getMessage() should contain ".concat(toS), (getM
+                    .indexOf(toS) != -1));
+        }
+        assertNotNull("getCause() must not return null", tE.getCause());
+        assertEquals("getCause() must return ".concat(tCause.toString()), tE
+                .getCause(), tCause);
+    }
+
+    /**
+     * Test for
+     * <code>InvalidAlgorithmParameterException(String, Throwable)</code>
+     * constructor Assertion: constructs InvalidAlgorithmParameterException when
+     * <code>cause</code> is null <code>msg</code> is null
+     */
+    public void testInvalidAlgorithmParameterException06() {
+        InvalidAlgorithmParameterException tE = new InvalidAlgorithmParameterException(
+                null, null);
+        assertNull("getMessage() must return null", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for
+     * <code>InvalidAlgorithmParameterException(String, Throwable)</code>
+     * constructor Assertion: constructs InvalidAlgorithmParameterException when
+     * <code>cause</code> is null <code>msg</code> is not null
+     */
+    public void testInvalidAlgorithmParameterException07() {
+        InvalidAlgorithmParameterException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new InvalidAlgorithmParameterException(msgs[i], null);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+
+    /**
+     * Test for
+     * <code>InvalidAlgorithmParameterException(String, Throwable)</code>
+     * constructor Assertion: constructs InvalidAlgorithmParameterException when
+     * <code>cause</code> is not null <code>msg</code> is null
+     */
+    public void testInvalidAlgorithmParameterException08() {
+        InvalidAlgorithmParameterException tE = new InvalidAlgorithmParameterException(
+                null, tCause);
+        if (tE.getMessage() != null) {
+            String toS = tCause.toString();
+            String getM = tE.getMessage();
+            assertTrue("getMessage() must should ".concat(toS), (getM
+                    .indexOf(toS) != -1));
+        }
+        assertNotNull("getCause() must not return null", tE.getCause());
+        assertEquals("getCause() must return ".concat(tCause.toString()), tE
+                .getCause(), tCause);
+    }
+
+    /**
+     * Test for
+     * <code>InvalidAlgorithmParameterException(String, Throwable)</code>
+     * constructor Assertion: constructs InvalidAlgorithmParameterException when
+     * <code>cause</code> is not null <code>msg</code> is not null
+     */
+    public void testInvalidAlgorithmParameterException09() {
+        InvalidAlgorithmParameterException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new InvalidAlgorithmParameterException(msgs[i], tCause);
+            String getM = tE.getMessage();
+            String toS = tCause.toString();
+            if (msgs[i].length() > 0) {
+                assertTrue("getMessage() must contain ".concat(msgs[i]), getM
+                        .indexOf(msgs[i]) != -1);
+                if (!getM.equals(msgs[i])) {
+                    assertTrue("getMessage() should contain ".concat(toS), getM
+                            .indexOf(toS) != -1);
+                }
+            }
+            assertNotNull("getCause() must not return null", tE.getCause());
+            assertEquals("getCause() must return ".concat(tCause.toString()),
+                    tE.getCause(), tCause);
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/InvalidKeyException2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/InvalidKeyException2Test.java
new file mode 100644
index 0000000..b54c0c2
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/InvalidKeyException2Test.java
@@ -0,0 +1,46 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.InvalidKeyException;
+
+public class InvalidKeyException2Test extends junit.framework.TestCase {
+
+    /**
+     * @tests java.security.InvalidKeyException#InvalidKeyException()
+     */
+    public void test_Constructor() {
+        // Test for method java.security.InvalidKeyException()
+        InvalidKeyException e = new InvalidKeyException();
+        assertNotNull("Constructor returned a null", e);
+        assertEquals("Failed toString test for constructed instance", "java.security.InvalidKeyException", e
+                .toString());
+    }
+
+    /**
+     * @tests java.security.InvalidKeyException#InvalidKeyException(java.lang.String)
+     */
+    public void test_ConstructorLjava_lang_String() {
+        // Test for method java.security.InvalidKeyException(java.lang.String)
+        InvalidKeyException e = new InvalidKeyException("test message");
+        assertNotNull("Constructor returned a null", e);
+        assertEquals("Failed toString test for constructed instance", 
+                        "java.security.InvalidKeyException: test message", e
+                .toString());
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/InvalidKeyExceptionTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/InvalidKeyExceptionTest.java
new file mode 100644
index 0000000..622682f
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/InvalidKeyExceptionTest.java
@@ -0,0 +1,188 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.InvalidKeyException;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>InvalidKeyException</code> class constructors and methods.
+ * 
+ */
+public class InvalidKeyExceptionTest extends TestCase {
+
+    public static void main(String[] args) {
+    }
+
+    /**
+     * Constructor for InvalidKeyExceptionTests.
+     * 
+     * @param arg0
+     */
+    public InvalidKeyExceptionTest(String arg0) {
+        super(arg0);
+    }
+
+    private static String[] msgs = {
+            "",
+            "Check new message",
+            "Check new message Check new message Check new message Check new message Check new message" };
+
+    private static Throwable tCause = new Throwable("Throwable for exception");
+
+    /**
+     * Test for <code>InvalidKeyException()</code> constructor Assertion:
+     * constructs InvalidKeyException with no detail message
+     */
+    public void testInvalidKeyException01() {
+        InvalidKeyException tE = new InvalidKeyException();
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>InvalidKeyException(String)</code> constructor
+     * Assertion: constructs InvalidKeyException with detail message msg.
+     * Parameter <code>msg</code> is not null.
+     */
+    public void testInvalidKeyException02() {
+        InvalidKeyException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new InvalidKeyException(msgs[i]);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+
+    /**
+     * Test for <code>InvalidKeyException(String)</code> constructor
+     * Assertion: constructs InvalidKeyException when <code>msg</code> is null
+     */
+    public void testInvalidKeyException03() {
+        String msg = null;
+        InvalidKeyException tE = new InvalidKeyException(msg);
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>InvalidKeyException(Throwable)</code> constructor
+     * Assertion: constructs InvalidKeyException when <code>cause</code> is
+     * null
+     */
+    public void testInvalidKeyException04() {
+        Throwable cause = null;
+        InvalidKeyException tE = new InvalidKeyException(cause);
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>InvalidKeyException(Throwable)</code> constructor
+     * Assertion: constructs InvalidKeyException when <code>cause</code> is
+     * not null
+     */
+    public void testInvalidKeyException05() {
+        InvalidKeyException tE = new InvalidKeyException(tCause);
+        if (tE.getMessage() != null) {
+            String toS = tCause.toString();
+            String getM = tE.getMessage();
+            assertTrue("getMessage() should contain ".concat(toS), (getM
+                    .indexOf(toS) != -1));
+        }
+        assertNotNull("getCause() must not return null", tE.getCause());
+        assertEquals("getCause() must return ".concat(tCause.toString()), tE
+                .getCause(), tCause);
+    }
+
+    /**
+     * Test for <code>InvalidKeyException(String, Throwable)</code>
+     * constructor Assertion: constructs InvalidKeyException when
+     * <code>cause</code> is null <code>msg</code> is null
+     */
+    public void testInvalidKeyException06() {
+        InvalidKeyException tE = new InvalidKeyException(null, null);
+        assertNull("getMessage() must return null", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>InvalidKeyException(String, Throwable)</code>
+     * constructor Assertion: constructs InvalidKeyException when
+     * <code>cause</code> is null <code>msg</code> is not null
+     */
+    public void testInvalidKeyException07() {
+        InvalidKeyException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new InvalidKeyException(msgs[i], null);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+
+    /**
+     * Test for <code>InvalidKeyException(String, Throwable)</code>
+     * constructor Assertion: constructs InvalidKeyException when
+     * <code>cause</code> is not null <code>msg</code> is null
+     */
+    public void testInvalidKeyException08() {
+        InvalidKeyException tE = new InvalidKeyException(null, tCause);
+        if (tE.getMessage() != null) {
+            String toS = tCause.toString();
+            String getM = tE.getMessage();
+            assertTrue("getMessage() must should ".concat(toS), (getM
+                    .indexOf(toS) != -1));
+        }
+        assertNotNull("getCause() must not return null", tE.getCause());
+        assertEquals("getCause() must return ".concat(tCause.toString()), tE
+                .getCause(), tCause);
+    }
+
+    /**
+     * Test for <code>InvalidKeyException(String, Throwable)</code>
+     * constructor Assertion: constructs InvalidKeyException when
+     * <code>cause</code> is not null <code>msg</code> is not null
+     */
+    public void testInvalidKeyException09() {
+        InvalidKeyException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new InvalidKeyException(msgs[i], tCause);
+            String getM = tE.getMessage();
+            String toS = tCause.toString();
+            if (msgs[i].length() > 0) {
+                assertTrue("getMessage() must contain ".concat(msgs[i]), getM
+                        .indexOf(msgs[i]) != -1);
+                if (!getM.equals(msgs[i])) {
+                    assertTrue("getMessage() should contain ".concat(toS), getM
+                            .indexOf(toS) != -1);
+                }
+            }
+            assertNotNull("getCause() must not return null", tE.getCause());
+            assertEquals("getCause() must return ".concat(tCause.toString()),
+                    tE.getCause(), tCause);
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/InvalidParameterException2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/InvalidParameterException2Test.java
new file mode 100644
index 0000000..2d721a2
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/InvalidParameterException2Test.java
@@ -0,0 +1,48 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.InvalidParameterException;
+
+public class InvalidParameterException2Test extends junit.framework.TestCase {
+
+    /**
+     * @tests java.security.InvalidParameterException#InvalidParameterException()
+     */
+    public void test_Constructor() {
+        // Test for method java.security.InvalidParameterException()
+        InvalidParameterException e = new InvalidParameterException();
+        assertEquals("Failed toString test for constructed instance", "java.security.InvalidParameterException", e
+                .toString());
+    }
+
+    /**
+     * @tests java.security.InvalidParameterException#InvalidParameterException(java.lang.String)
+     */
+    public void test_ConstructorLjava_lang_String() {
+        // Test for method
+        // java.security.InvalidParameterException(java.lang.String)
+        InvalidParameterException e = new InvalidParameterException(
+                "test message");
+        assertEquals("Failed toString test for constructed instance",
+                
+                                "java.security.InvalidParameterException: test message", e
+                        .toString()
+                        );
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/InvalidParameterExceptionTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/InvalidParameterExceptionTest.java
new file mode 100644
index 0000000..51707cc
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/InvalidParameterExceptionTest.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.InvalidParameterException;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>InvalidParameterException</code> class constructors and
+ * methods.
+ * 
+ */
+public class InvalidParameterExceptionTest extends TestCase {
+
+    public static void main(String[] args) {
+    }
+
+    /**
+     * Constructor for InvalidParameterExceptionTests.
+     * 
+     * @param arg0
+     */
+    public InvalidParameterExceptionTest(String arg0) {
+        super(arg0);
+    }
+
+    static String[] msgs = {
+            "",
+            "Check new message",
+            "Check new message Check new message Check new message Check new message Check new message" };
+
+    static Throwable tCause = new Throwable("Throwable for exception");
+
+    /**
+     * Test for <code>InvalidParameterException()</code> constructor
+     * Assertion: constructs InvalidParameterException with no detail message
+     */
+    public void testInvalidParameterException01() {
+        InvalidParameterException tE = new InvalidParameterException();
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>InvalidParameterException(String)</code> constructor
+     * Assertion: constructs InvalidParameterException with detail message msg.
+     * Parameter <code>msg</code> is not null.
+     */
+    public void testInvalidParameterException02() {
+        InvalidParameterException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new InvalidParameterException(msgs[i]);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+
+    /**
+     * Test for <code>InvalidParameterException(String)</code> constructor
+     * Assertion: constructs InvalidParameterException when <code>msg</code>
+     * is null
+     */
+    public void testInvalidParameterException03() {
+        String msg = null;
+        InvalidParameterException tE = new InvalidParameterException(msg);
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KSCallbackHandlerProtectionTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KSCallbackHandlerProtectionTest.java
new file mode 100644
index 0000000..12c3524
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KSCallbackHandlerProtectionTest.java
@@ -0,0 +1,72 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.KeyStore;
+
+import javax.security.auth.callback.CallbackHandler;
+
+import org.apache.harmony.security.tests.support.tmpCallbackHandler;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>KeyStore.CallbackHandlerProtection> class constructor and methods
+ * 
+ */
+
+public class KSCallbackHandlerProtectionTest extends TestCase {
+
+    /**
+     * Constructor for KSCallbackHandlerProtectionTest.
+     * @param arg0
+     */
+    public KSCallbackHandlerProtectionTest(String arg0) {
+        super(arg0);
+    }
+    
+    /**
+     * Test for <code>KeyStore.CallbackHandlerProtection(CallbackHandler handler)</code>
+     * constructor
+     * Assertion: throws NullPointerException when handler is null
+     */
+    public void testCallbackHandlerProtection() {
+        try {
+            new KeyStore.CallbackHandlerProtection(null);
+            fail("NullPointerException must be thrown when handler is null");
+        } catch (NullPointerException e) {
+        }
+    }
+    
+    /**
+     * Test for <code>getCallbackHandler()</code> method
+     * Assertion: returns CallbackHandler 
+     */
+    public void testGetCallBackHandler() {
+        CallbackHandler cbh = new tmpCallbackHandler();
+        KeyStore.CallbackHandlerProtection ksCBH = new KeyStore.CallbackHandlerProtection(cbh);
+        assertEquals("Incorrect CallbackHandler", cbh,
+                ksCBH.getCallbackHandler());
+    }
+}
+
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KSPasswordProtectionTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KSPasswordProtectionTest.java
new file mode 100644
index 0000000..a3ea0ed
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KSPasswordProtectionTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.KeyStore;
+
+import javax.security.auth.DestroyFailedException;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>KeyStore.PasswordProtection</code> class constructor and methods
+ * 
+ */
+
+public class KSPasswordProtectionTest extends TestCase {
+
+    /**
+     * Constructor for KSPasswordProtectionTest.
+     * @param arg0
+     */
+    public KSPasswordProtectionTest(String arg0) {
+        super(arg0);
+    }
+    
+    /**
+     * Test for <code>KeyStore.PasswordProtection(char[] password)</code> constructor
+     * and the following methods 
+     * <code>getPassword()<code>
+     * <code>destroy()<code>
+     * <code>isDestroyed()<code>
+     * Assertions: constructor created new PasswordProtection object
+     * getPassword() returns password or throws IllegalArgumentException
+     * if PasswordProtection is destroyed
+     */
+    public void testGetPassword() throws DestroyFailedException {
+        char [] pass = {'a', 'b', 'c'};
+        KeyStore.PasswordProtection ksPWP = new KeyStore.PasswordProtection(pass);
+        char [] rPass = ksPWP.getPassword();
+        assertFalse("PasswordProtection Should not be destroyed", ksPWP.isDestroyed());        
+        assertEquals("Incorrect password length", pass.length, rPass.length);
+        for (int i = 0; i < pass.length; i++) {
+            assertEquals("Incorrect password (item: ".concat(Integer.toString(i))
+                    .concat(")"), pass[i], rPass[i]);
+        }
+        ksPWP.destroy();
+        assertTrue("PasswordProtection must be destroyed", ksPWP.isDestroyed());
+        try {
+            ksPWP.getPassword();
+            fail("IllegalStateException must be thrown because PasswordProtection is destroyed");
+        } catch (IllegalStateException e) {
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KSPrivateKeyEntryTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KSPrivateKeyEntryTest.java
new file mode 100644
index 0000000..6382cf7
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KSPrivateKeyEntryTest.java
@@ -0,0 +1,214 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+
+import org.apache.harmony.security.tests.support.cert.MyCertificate;
+
+import junit.framework.TestCase;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Tests for <code>KeyStore.PrivateKeyEntry</code>  class constructor and methods 
+ * 
+ */
+
+public class KSPrivateKeyEntryTest extends TestCase {
+
+    /**
+     * Constructor for KSPrivateKeyEntryTest.
+     * @param arg0
+     */
+    public KSPrivateKeyEntryTest(String arg0) {
+        super(arg0);
+    }
+    private PrivateKey testPrivateKey;
+    private Certificate [] testChain;
+    
+    private void createParams(boolean diffCerts, boolean diffKeys) {
+        byte[] encoded = {(byte)0, (byte)1, (byte)2, (byte)3};
+        testChain = new Certificate[5];
+        for (int i = 0; i < testChain.length; i++) {
+            String s = (diffCerts ? Integer.toString(i) : "NEW");
+            testChain[i] = new MyCertificate("MY_TEST_CERTIFICATE_"
+                    .concat(s), encoded);
+        }
+        testPrivateKey = (diffKeys ? (PrivateKey)new tmpPrivateKey() : 
+            (PrivateKey)new tmpPrivateKey(testChain[0].getPublicKey().getAlgorithm()));
+    }
+    
+    /**
+     * Test for <code>PrivateKeyEntry(PrivateKey privateKey, Certificate[] chain)</code>
+     * constructor
+     * Assertion: throws NullPointerException when privateKey is null
+     */
+    public void testPrivateKeyEntry01() {
+        Certificate[] certs = new MyCertificate[1];//new Certificate[1];
+        PrivateKey pk = null;
+        try {
+            new KeyStore.PrivateKeyEntry(pk, certs);
+            fail("NullPointerException must be thrown when privateKey is null");
+        } catch (NullPointerException e) {
+        }
+    }
+
+    /**
+     * Test for <code>PrivateKeyEntry(PrivateKey privateKey, Certificate[] chain)</code>
+     * constructor
+     * Assertion: throws NullPointerException when chain is null
+     * and throws IllegalArgumentException when chain length is 0
+     */
+    public void testPrivateKeyEntry02() {
+        Certificate[] chain = null;
+        PrivateKey pk = new tmpPrivateKey();
+        try {
+            new KeyStore.PrivateKeyEntry(pk, chain);
+            fail("NullPointerException must be thrown when chain is null");
+        } catch (NullPointerException e) {
+        }
+        try {
+            chain = new Certificate[0];
+            new KeyStore.PrivateKeyEntry(pk, chain);
+            fail("IllegalArgumentException must be thrown when chain length is 0");
+        } catch (IllegalArgumentException e) {
+        }
+    }
+    /**
+     * Test for <code>PrivateKeyEntry(PrivateKey privateKey, Certificate[] chain)</code>
+     * constructor
+     * Assertion: throws IllegalArgumentException when chain contains certificates 
+     * of different types
+     */
+    public void testPrivateKeyEntry03() {
+        createParams(true, false);
+        try {
+            new KeyStore.PrivateKeyEntry(testPrivateKey, testChain);
+            fail("IllegalArgumentException must be thrown when chain contains certificates of different types");
+        } catch (IllegalArgumentException e) {
+        }
+    }
+    
+    /**
+     * Test for <code>PrivateKeyEntry(PrivateKey privateKey, Certificate[] chain)</code>
+     * constructor
+     * Assertion: throws IllegalArgumentException when algorithm of privateKey 
+     * does not match the algorithm of PublicKey in the end certificate (with 0 index)
+     */
+    public void testPrivateKeyEntry04() {
+        createParams(false, true);               
+        try {
+            new KeyStore.PrivateKeyEntry(testPrivateKey, testChain);
+            fail("IllegalArgumentException must be thrown when key algorithms do not match");
+        } catch (IllegalArgumentException e) {       
+        }
+    }
+
+    /**
+     * Test for <code>getPrivateKey()</code> method
+     * Assertion: returns PrivateKey object
+     */
+    public void testGetPrivateKey() {
+        createParams(false, false);
+        KeyStore.PrivateKeyEntry ksPKE = new KeyStore.PrivateKeyEntry(
+                testPrivateKey, testChain);
+        assertEquals("Incorrect PrivateKey", testPrivateKey, ksPKE
+                .getPrivateKey());
+    }
+    
+    /**
+     * Test for <code>getCertificateChain()</code> method Assertion: returns
+     * array of the Certificates corresponding to chain
+     */
+    public void testGetCertificateChain() {
+        createParams(false, false);
+        KeyStore.PrivateKeyEntry ksPKE = new KeyStore.PrivateKeyEntry(
+                testPrivateKey, testChain);
+        Certificate[] res = ksPKE.getCertificateChain();
+        assertEquals("Incorrect chain length", testChain.length, res.length);
+        for (int i = 0; i < res.length; i++) {
+            assertEquals("Incorrect chain element: "
+                    .concat(Integer.toString(i)), testChain[i], res[i]);
+        }
+    }
+    
+    /**
+     * Test for <code>getCertificate()</code> method
+     * Assertion: returns end Certificate (with 0 index in chain)
+     */
+    public void testGetCertificate() {
+        createParams(false, false);
+        KeyStore.PrivateKeyEntry ksPKE = new KeyStore.PrivateKeyEntry(
+                testPrivateKey, testChain);
+        Certificate res = ksPKE.getCertificate();
+        assertEquals("Incorrect end certificate (number 0)", testChain[0], res);
+    }
+
+    /**
+     * Test for <code>toString()</code> method
+     * Assertion: returns non null String
+     */
+    public void testToString() {
+        createParams(false, false);
+        KeyStore.PrivateKeyEntry ksPKE = new KeyStore.PrivateKeyEntry(
+                testPrivateKey, testChain);
+        String res = ksPKE.toString();
+        assertNotNull("toString() returns null", res);
+    }
+
+    public static Test suite() {
+        return new TestSuite(KSPrivateKeyEntryTest.class);
+    }
+
+    public static void main(String args[]) {
+        junit.textui.TestRunner.run(suite());
+    }
+
+    private static class tmpPrivateKey implements PrivateKey {
+        private String alg = "My algorithm";
+
+        public String getAlgorithm() {
+            return alg;
+        }
+
+        public String getFormat() {
+            return "My Format";
+        }
+
+        public byte[] getEncoded() {
+            return new byte[1];
+        }
+
+        public tmpPrivateKey() {
+        }
+
+        public tmpPrivateKey(String algorithm) {
+            super();
+            alg = algorithm;
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KSSecretKeyEntryTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KSSecretKeyEntryTest.java
new file mode 100644
index 0000000..cb1ad25
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KSSecretKeyEntryTest.java
@@ -0,0 +1,89 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.KeyStore;
+
+import javax.crypto.SecretKey;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>KeyStore.SecretKeyEntry</code> class constructor and methods 
+ * 
+ */
+
+public class KSSecretKeyEntryTest extends TestCase {
+
+    /**
+     * Constructor for KSSecretKeyTest.
+     * @param arg0
+     */
+    public KSSecretKeyEntryTest(String arg0) {
+        super(arg0);
+    }
+    /**
+     * Test for <code>SecretKeyEntry(SecretKey secretKey)</code> constructor
+     * Assertion: throws NullPointerException when secretKey is null
+     */
+    public void testSecretKeyEntry() {
+        SecretKey sk = null;
+        try {
+            new KeyStore.SecretKeyEntry(sk);
+            fail("NullPointerException must be thrown when secretKey is null");
+        } catch(NullPointerException e) {
+        }
+    }
+    
+    /**
+     * Test for <code>getSecretKey()</code> method
+     * Assertion: returns SecretKey from the given entry
+     */
+    public void testGetSecretKey() {
+        SecretKey sk = new tmpSecretKey();
+        KeyStore.SecretKeyEntry ske = new KeyStore.SecretKeyEntry(sk);
+        assertEquals("Incorrect SecretKey", sk, ske.getSecretKey());
+    }
+   
+    /**
+     * Test for <code>toString()</code> method
+     * Assertion: returns non null string
+     */
+    public void testToString() {
+        SecretKey sk = new tmpSecretKey();
+        KeyStore.SecretKeyEntry ske = new KeyStore.SecretKeyEntry(sk);
+        assertNotNull("toString() returns null string", ske.toString());
+    }
+}
+
+class tmpSecretKey implements SecretKey {
+    public String getAlgorithm() {
+        return "My algorithm";
+    }
+    public String getFormat() {
+        return "My Format";
+    }
+    public byte[] getEncoded() {
+        return new byte[1];
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KSTrustedCertificateEntryTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KSTrustedCertificateEntryTest.java
new file mode 100644
index 0000000..a4a15d3
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KSTrustedCertificateEntryTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.KeyStore;
+import java.security.cert.Certificate;
+
+import org.apache.harmony.security.tests.support.cert.MyCertificate;
+
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>KeyStore.TrustedCertificateEntry</code> class constructor and methods 
+ * 
+ */
+
+public class KSTrustedCertificateEntryTest extends TestCase {
+
+    /**
+     * Test for <codfe>KeyStore.TrustedCertificateEntry(Certificate trustCert)</code>
+     * constructor
+     * Assertion: throws NullPointerException when trustCert is null
+     */
+    public void testTrustedCertificateEntry() {
+        Certificate cert = null;
+        try {
+            new KeyStore.TrustedCertificateEntry(cert);
+            fail("NullPointerException must be thrown when trustCert is null");
+        } catch (NullPointerException e) {
+        }
+    }
+    
+    /**
+     * Test for <codfe>getTrustedCertificate()</code> method
+     * Assertion: returns trusted Certificate from goven entry 
+     */
+    public void testGetTrustedCertificate() {
+        Certificate cert = new MyCertificate("TEST", new byte[10]);
+        KeyStore.TrustedCertificateEntry ksTCE = 
+                new KeyStore.TrustedCertificateEntry(cert);
+        assertEquals("Incorrect certificate", cert, ksTCE.getTrustedCertificate());
+    }
+
+    /**
+     * Test for <codfe>toString()</code> method
+     * Assertion: returns non null string 
+     */
+    public void testToString() {
+        Certificate cert = new MyCertificate("TEST", new byte[10]);
+        KeyStore.TrustedCertificateEntry ksTCE = 
+                new KeyStore.TrustedCertificateEntry(cert);
+        assertNotNull("toString() returns null string", ksTCE.toString());
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyException2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyException2Test.java
new file mode 100644
index 0000000..4b4caf4
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyException2Test.java
@@ -0,0 +1,43 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.KeyException;
+
+public class KeyException2Test extends junit.framework.TestCase {
+
+    /**
+     * @tests java.security.KeyException#KeyException()
+     */
+    public void test_Constructor() {
+        // Test for method java.security.KeyException()
+        KeyException e = new KeyException();
+        assertEquals("Failed toString test for constructed instance", "java.security.KeyException", e
+                .toString());
+    }
+
+    /**
+     * @tests java.security.KeyException#KeyException(java.lang.String)
+     */
+    public void test_ConstructorLjava_lang_String() {
+        // Test for method java.security.KeyException(java.lang.String)
+        KeyException e = new KeyException("test message");
+        assertEquals("Failed toString test for constructed instance", "java.security.KeyException: test message", e
+                .toString());
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyExceptionTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyExceptionTest.java
new file mode 100644
index 0000000..b694fab
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyExceptionTest.java
@@ -0,0 +1,186 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.KeyException;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>KeyException</code> class constructors and methods.
+ * 
+ */
+public class KeyExceptionTest extends TestCase {
+
+    public static void main(String[] args) {
+    }
+
+    /**
+     * Constructor for KeyExceptionTests.
+     * 
+     * @param arg0
+     */
+    public KeyExceptionTest(String arg0) {
+        super(arg0);
+    }
+
+    private static String[] msgs = {
+            "",
+            "Check new message",
+            "Check new message Check new message Check new message Check new message Check new message" };
+
+    private static Throwable tCause = new Throwable("Throwable for exception");
+
+    /**
+     * Test for <code>KeyException()</code> constructor Assertion: constructs
+     * KeyException with no detail message
+     */
+    public void testKeyException01() {
+        KeyException tE = new KeyException();
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>KeyException(String)</code> constructor Assertion:
+     * constructs KeyException with detail message msg. Parameter
+     * <code>msg</code> is not null.
+     */
+    public void testKeyException02() {
+        KeyException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new KeyException(msgs[i]);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+
+    /**
+     * Test for <code>KeyException(String)</code> constructor Assertion:
+     * constructs KeyException when <code>msg</code> is null
+     */
+    public void testKeyException03() {
+        String msg = null;
+        KeyException tE = new KeyException(msg);
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>KeyException(Throwable)</code> constructor Assertion:
+     * constructs KeyException when <code>cause</code> is null
+     */
+    public void testKeyException04() {
+        Throwable cause = null;
+        KeyException tE = new KeyException(cause);
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>KeyException(Throwable)</code> constructor Assertion:
+     * constructs KeyException when <code>cause</code> is not null
+     */
+    public void testKeyException05() {
+        KeyException tE = new KeyException(tCause);
+        if (tE.getMessage() != null) {
+            String toS = tCause.toString();
+            String getM = tE.getMessage();
+            assertTrue("getMessage() should contain ".concat(toS), (getM
+                    .indexOf(toS) != -1));
+        }
+        assertNotNull("getCause() must not return null", tE.getCause());
+        assertEquals("getCause() must return ".concat(tCause.toString()), tE
+                .getCause(), tCause);
+    }
+
+    /**
+     * Test for <code>KeyException(String, Throwable)</code> constructor
+     * Assertion: constructs KeyException when <code>cause</code> is null
+     * <code>msg</code> is null
+     */
+    public void testKeyException06() {
+        KeyException tE = new KeyException(null, null);
+        assertNull("getMessage() must return null", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>KeyException(String, Throwable)</code> constructor
+     * Assertion: constructs KeyException when <code>cause</code> is null
+     * <code>msg</code> is not null
+     */
+    public void testKeyException07() {
+        KeyException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new KeyException(msgs[i], null);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+
+    /**
+     * Test for <code>KeyException(String, Throwable)</code> constructor
+     * Assertion: constructs KeyException when <code>cause</code> is not null
+     * <code>msg</code> is null
+     */
+    public void testKeyException08() {
+        KeyException tE = new KeyException(null, tCause);
+        if (tE.getMessage() != null) {
+            String toS = tCause.toString();
+            String getM = tE.getMessage();
+            assertTrue("getMessage() must should ".concat(toS), (getM
+                    .indexOf(toS) != -1));
+        }
+        assertNotNull("getCause() must not return null", tE.getCause());
+        assertEquals("getCause() must return ".concat(tCause.toString()), tE
+                .getCause(), tCause);
+    }
+
+    /**
+     * Test for <code>KeyException(String, Throwable)</code> constructor
+     * Assertion: constructs KeyException when <code>cause</code> is not null
+     * <code>msg</code> is not null
+     */
+    public void testKeyException09() {
+        KeyException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new KeyException(msgs[i], tCause);
+            String getM = tE.getMessage();
+            String toS = tCause.toString();
+            if (msgs[i].length() > 0) {
+                assertTrue("getMessage() must contain ".concat(msgs[i]), getM
+                        .indexOf(msgs[i]) != -1);
+                if (!getM.equals(msgs[i])) {
+                    assertTrue("getMessage() should contain ".concat(toS), getM
+                            .indexOf(toS) != -1);
+                }
+            }
+            assertNotNull("getCause() must not return null", tE.getCause());
+            assertEquals("getCause() must return ".concat(tCause.toString()),
+                    tE.getCause(), tCause);
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyFactory2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyFactory2Test.java
new file mode 100644
index 0000000..4a59623
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyFactory2Test.java
@@ -0,0 +1,500 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.KeyFactorySpi;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.Vector;
+
+public class KeyFactory2Test extends junit.framework.TestCase {
+
+    private static final String KEYFACTORY_ID = "KeyFactory.";
+
+    private String[] keyfactAlgs = null;
+
+    private String providerName = null;
+
+    static class KeepAlive extends Thread {
+        int sleepTime, iterations;
+
+        public KeepAlive(int sleepTime, int iterations) {
+            this.sleepTime = sleepTime;
+            this.iterations = iterations;
+        }
+
+        public void run() {
+            synchronized (this) {
+                this.notify();
+            }
+            for (int i = 0; i < iterations; i++) {
+                try {
+                    Thread.sleep(sleepTime);
+                    System.out.print("[KA]");
+                } catch (InterruptedException e) {
+                    System.out.print("[I]");
+                    break;
+                }
+            }
+        }
+    }
+
+    private KeepAlive createKeepAlive(String alg) {
+        if (alg.equals("RSA")) {
+            // 32 minutes
+            KeepAlive keepalive = new KeepAlive(240000, 8);
+            synchronized (keepalive) {
+                keepalive.start();
+                try {
+                    keepalive.wait();
+                } catch (InterruptedException e) {
+                    // ignore
+                }
+            }
+            return keepalive;
+        }
+        return null;
+    }
+
+    /**
+     * @tests java.security.KeyFactory#KeyFactory(java.security.KeyFactorySpi,
+     *        java.security.Provider, java.lang.String)
+     */
+    public void test_constructor() {
+        KeyFactorySpi kfs = new KeyFactorySpiStub();
+
+        try {
+            new KeyFactoryStub(null, null, null);
+        } catch (Exception e) {
+            fail("Unexpected exception " + e.getMessage());
+        }
+
+        Provider[] providers = Security.getProviders("KeyFactory.DSA");
+        if (providers != null) {
+            for (int i = 0; i < providers.length; i++) {
+                KeyFactoryStub kf = new KeyFactoryStub(kfs, providers[i],
+                        "algorithm name");
+                assertEquals("algorithm name", kf.getAlgorithm());
+                assertEquals(providers[i], kf.getProvider());
+            }
+        } else {
+            fail("No providers support KeyFactory.DSA");
+        }
+    }
+
+    /**
+     * @tests java.security.KeyFactory#generatePrivate(java.security.spec.KeySpec)
+     */
+    public void test_generatePrivateLjava_security_spec_KeySpec() {
+        // Test for method java.security.PrivateKey
+        // java.security.KeyFactory.generatePrivate(java.security.spec.KeySpec)
+        for (int i = 0; i < keyfactAlgs.length; i++) {
+            try {
+                KeyFactory fact = KeyFactory.getInstance(keyfactAlgs[i],
+                        providerName);
+                KeyPairGenerator keyGen = KeyPairGenerator
+                        .getInstance(keyfactAlgs[i]);
+                SecureRandom random = new SecureRandom(); // We don't use
+                // getInstance
+                keyGen.initialize(1024, random);
+                KeepAlive keepalive = createKeepAlive(keyfactAlgs[i]);
+                KeyPair keys = keyGen.generateKeyPair();
+                if (keepalive != null) {
+                    keepalive.interrupt();
+                }
+
+                KeySpec privateKeySpec = fact.getKeySpec(keys.getPrivate(),
+                        getPrivateKeySpecClass(keyfactAlgs[i]));
+                PrivateKey privateKey = fact.generatePrivate(privateKeySpec);
+                boolean samePrivate = Arrays.equals(keys.getPrivate()
+                        .getEncoded(), privateKey.getEncoded());
+                assertTrue(
+                        "generatePrivate generated different key for algorithm "
+                                + keyfactAlgs[i], samePrivate);
+                fact.generatePrivate(new PKCS8EncodedKeySpec(keys.getPrivate()
+                        .getEncoded()));
+            } catch (InvalidKeySpecException e) {
+                fail("invalid key spec for algorithm " + keyfactAlgs[i]);
+            } catch (NoSuchAlgorithmException e) {
+                fail("getInstance did not find algorithm " + keyfactAlgs[i]);
+            } catch (NoSuchProviderException e) {
+                fail("getInstance did not find provider " + providerName);
+            }
+        }
+    }
+
+    /**
+     * @tests java.security.KeyFactory#generatePublic(java.security.spec.KeySpec)
+     */
+    public void test_generatePublicLjava_security_spec_KeySpec() {
+        // Test for method java.security.PublicKey
+        // java.security.KeyFactory.generatePublic(java.security.spec.KeySpec)
+        for (int i = 0; i < keyfactAlgs.length; i++) {
+            try {
+                KeyFactory fact = KeyFactory.getInstance(keyfactAlgs[i],
+                        providerName);
+                KeyPairGenerator keyGen = KeyPairGenerator
+                        .getInstance(keyfactAlgs[i]);
+                // We don't use getInstance
+                SecureRandom random = new SecureRandom();
+                keyGen.initialize(1024, random);
+                KeepAlive keepalive = createKeepAlive(keyfactAlgs[i]);
+                KeyPair keys = keyGen.generateKeyPair();
+                if (keepalive != null) {
+                    keepalive.interrupt();
+                }
+                KeySpec publicKeySpec = fact.getKeySpec(keys.getPublic(),
+                        getPublicKeySpecClass(keyfactAlgs[i]));
+                PublicKey publicKey = fact.generatePublic(publicKeySpec);
+                boolean samePublic = Arrays.equals(keys.getPublic()
+                        .getEncoded(), publicKey.getEncoded());
+                assertTrue(
+                        "generatePublic generated different key for algorithm "
+                                + keyfactAlgs[i], samePublic);
+            } catch (NoSuchAlgorithmException e) {
+                fail("getInstance did not find algorithm " + keyfactAlgs[i]);
+            } catch (NoSuchProviderException e) {
+                fail("getInstance did not find provider " + providerName);
+            } catch (InvalidKeySpecException e) {
+                fail("invalid key spec for algorithm " + keyfactAlgs[i]);
+            }
+        }
+    }
+
+    /**
+     * @tests java.security.KeyFactory#getAlgorithm()
+     */
+    public void test_getAlgorithm() {
+        // Test for method java.lang.String
+        // java.security.KeyFactory.getAlgorithm()
+        for (int i = 0; i < keyfactAlgs.length; i++) {
+            try {
+                KeyFactory fact = KeyFactory.getInstance(keyfactAlgs[i],
+                        providerName);
+                assertTrue("getAlgorithm ok for algorithm " + keyfactAlgs[i],
+                        fact.getAlgorithm().equals(keyfactAlgs[i]));
+            } catch (NoSuchAlgorithmException e) {
+                fail("getInstance did not find algorithm " + keyfactAlgs[i]);
+            } catch (NoSuchProviderException e) {
+                fail("getInstance did not find provider " + providerName);
+            }
+        }// end for
+    }
+
+    /**
+     * @tests java.security.KeyFactory#getInstance(java.lang.String)
+     */
+    public void test_getInstanceLjava_lang_String() {
+        // Test for method java.security.KeyFactory
+        // java.security.KeyFactory.getInstance(java.lang.String)
+        for (int i = 0; i < keyfactAlgs.length; i++) {
+            try {
+                assertNotNull(KeyFactory.getInstance(keyfactAlgs[i]));
+            } catch (NoSuchAlgorithmException e) {
+                fail("getInstance did not find algorithm " + keyfactAlgs[i]);
+            }
+        }// end for
+    }
+
+    /**
+     * @tests java.security.KeyFactory#getInstance(java.lang.String,
+     *        java.lang.String)
+     */
+    public void test_getInstanceLjava_lang_StringLjava_lang_String() {
+
+        // Test1: Test for method java.security.KeyFactory
+        // java.security.KeyFactory.getInstance(java.lang.String,
+        // java.lang.String)
+        try {
+            Provider[] providers = Security.getProviders("KeyFactory.DSA");
+            if (providers != null) {
+                for (int i = 0; i < providers.length; i++) {
+                    KeyFactory.getInstance("DSA", providers[i].getName());
+                }// end for
+            } else {
+                fail("No providers support KeyFactory.DSA");
+            }
+        } catch (NoSuchAlgorithmException e) {
+            fail("getInstance did not find algorithm");
+        } catch (NoSuchProviderException e) {
+            fail("getInstance did not find the provider");
+        }
+
+        // Test2: Test with null provider name
+        try {
+            KeyFactory.getInstance("DSA", (String) null);
+            fail("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // Expected
+        } catch (Exception e) {
+            fail("Expected IllegalArgumentException, got " + e);
+        }
+    }
+
+    /**
+     * @tests java.security.KeyFactory#getInstance(java.lang.String,
+     *        java.lang.String)
+     */
+    public void test_getInstanceLjava_lang_StringLjava_security_Provider() {
+
+        // Test1: Test for method java.security.KeyFactory
+        // java.security.KeyFactory.getInstance(java.lang.String,
+        // java.security.Provider)
+        try {
+            Provider[] providers = Security.getProviders("KeyFactory.DSA");
+            if (providers != null) {
+                for (int i = 0; i < providers.length; i++) {
+                    KeyFactory.getInstance("DSA", providers[i]);
+                }// end for
+            } else {
+                fail("No providers support KeyFactory.DSA");
+            }
+        } catch (NoSuchAlgorithmException e) {
+            fail("getInstance did not find algorithm");
+        } catch (Exception e) {
+            fail("unexpected exception " + e.getMessage());
+        }
+
+        // Test2: Test with null provider name
+        try {
+            KeyFactory.getInstance("DSA", (Provider) null);
+            fail("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // Expected
+        } catch (Exception e) {
+            fail("Expected IllegalArgumentException, got " + e);
+        }
+    }
+
+    /**
+     * @tests java.security.KeyFactory#getKeySpec(java.security.Key,
+     *        java.lang.Class)
+     */
+    public void test_getKeySpecLjava_security_KeyLjava_lang_Class() {
+        // Test for method java.security.spec.KeySpec
+        // java.security.KeyFactory.getKeySpec(java.security.Key,
+        // java.lang.Class)
+        for (int i = 0; i < keyfactAlgs.length; i++) {
+            try {
+                KeyFactory fact = KeyFactory.getInstance(keyfactAlgs[i],
+                        providerName);
+                KeyPairGenerator keyGen = KeyPairGenerator
+                        .getInstance(keyfactAlgs[i]);
+
+                // We don't use getInstance
+                SecureRandom random = new SecureRandom();
+                keyGen.initialize(1024, random);
+                KeepAlive keepalive = createKeepAlive(keyfactAlgs[i]);
+                KeyPair keys = keyGen.generateKeyPair();
+                if (keepalive != null) {
+                    keepalive.interrupt();
+                }
+                KeySpec privateKeySpec = fact.getKeySpec(keys.getPrivate(),
+                        getPrivateKeySpecClass(keyfactAlgs[i]));
+                KeySpec publicKeySpec = fact.getKeySpec(keys.getPublic(),
+                        getPublicKeySpecClass(keyfactAlgs[i]));
+                PrivateKey privateKey = fact.generatePrivate(privateKeySpec);
+                PublicKey publicKey = fact.generatePublic(publicKeySpec);
+                boolean samePublic = Arrays.equals(keys.getPublic()
+                        .getEncoded(), publicKey.getEncoded());
+                boolean samePrivate = Arrays.equals(keys.getPrivate()
+                        .getEncoded(), privateKey.getEncoded());
+                assertTrue(
+                        "generatePrivate generated different key for algorithm "
+                                + keyfactAlgs[i], samePrivate);
+                assertTrue(
+                        "generatePublic generated different key for algorithm "
+                                + keyfactAlgs[i], samePublic);
+                KeySpec encodedSpec = fact.getKeySpec(keys.getPublic(),
+                        X509EncodedKeySpec.class);
+                assertTrue("improper key spec for encoded public key",
+                        encodedSpec.getClass().equals(X509EncodedKeySpec.class));
+                encodedSpec = fact.getKeySpec(keys.getPrivate(),
+                        PKCS8EncodedKeySpec.class);
+                assertTrue("improper key spec for encoded private key",
+                        encodedSpec.getClass()
+                                .equals(PKCS8EncodedKeySpec.class));
+            } catch (NoSuchAlgorithmException e) {
+                fail("getInstance did not find algorithm " + keyfactAlgs[i]);
+            } catch (NoSuchProviderException e) {
+                fail("getInstance did not find provider " + providerName);
+            } catch (InvalidKeySpecException e) {
+                fail("invalid key spec for algorithm " + keyfactAlgs[i]);
+            }
+        }
+    }
+
+    /**
+     * @tests java.security.KeyFactory#getProvider()
+     */
+    public void test_getProvider() {
+        // Test for method java.security.Provider
+        // java.security.KeyFactory.getProvider()
+        for (int i = 0; i < keyfactAlgs.length; i++) {
+            try {
+                KeyFactory fact = KeyFactory.getInstance(keyfactAlgs[i]);
+                Provider p = fact.getProvider();
+                assertNotNull("provider is null for algorithm "
+                        + keyfactAlgs[i], p);
+            } catch (NoSuchAlgorithmException e) {
+                fail("getInstance did not find algorithm " + keyfactAlgs[i]);
+            }
+        }// end for
+    }
+
+    /**
+     * @tests java.security.KeyFactory#translateKey(java.security.Key)
+     */
+    public void test_translateKeyLjava_security_Key() {
+        // Test for method java.security.Key
+        // java.security.KeyFactory.translateKey(java.security.Key)
+        for (int i = 0; i < keyfactAlgs.length; i++) {
+            try {
+                KeyFactory fact = KeyFactory.getInstance(keyfactAlgs[i],
+                        providerName);
+                KeyPairGenerator keyGen = KeyPairGenerator
+                        .getInstance(keyfactAlgs[i]);
+
+                // We don't use getInstance
+                SecureRandom random = new SecureRandom();
+                keyGen.initialize(1024, random);
+                KeepAlive keepalive = createKeepAlive(keyfactAlgs[i]);
+                KeyPair keys = keyGen.generateKeyPair();
+                if (keepalive != null) {
+                    keepalive.interrupt();
+                }
+                fact.translateKey(keys.getPrivate());
+            } catch (NoSuchAlgorithmException e) {
+                fail("getInstance did not find algorithm " + keyfactAlgs[i]);
+            } catch (NoSuchProviderException e) {
+                fail("getInstance did not find provider " + providerName);
+            } catch (InvalidKeyException e) {
+                fail("generatePublic did not generate right spec for algorithm "
+                        + keyfactAlgs[i]);
+            }
+        }
+    }
+
+    protected void setUp() {
+        if (keyfactAlgs == null) {
+            Provider[] providers = Security.getProviders();
+            // Arbitrarily use the first provider that supports
+            // KeyFactory algorithms
+            for (Provider provider : providers) {
+                providerName = provider.getName();
+                keyfactAlgs = getKeyFactoryAlgorithms(providerName);
+                if (keyfactAlgs.length != 0) {
+                    break;
+                }
+            }
+        }
+    }
+
+    /*
+     * Returns the key algorithms that the given provider supports.
+     */
+    private String[] getKeyFactoryAlgorithms(String providerName) {
+        Vector<String> algs = new Vector<String>();
+
+        Provider provider = Security.getProvider(providerName);
+        if (provider == null)
+            return new String[0];
+        Enumeration e = provider.keys();
+        while (e.hasMoreElements()) {
+            String algorithm = (String) e.nextElement();
+            if (algorithm.startsWith(KEYFACTORY_ID) && !algorithm.contains(" ")) {
+                algs.addElement(algorithm.substring(KEYFACTORY_ID.length()));
+            }
+        }
+
+        return (String[]) algs.toArray(new String[algs.size()]);
+    }
+
+    /**
+     * Returns the public key spec class for a given algorithm, or null if it is
+     * not known.
+     */
+    private Class getPrivateKeySpecClass(String algName) {
+        if (algName.equals("RSA")) {
+            return java.security.spec.RSAPrivateCrtKeySpec.class;
+        }
+        if (algName.equals("DSA")) {
+            return java.security.spec.DSAPrivateKeySpec.class;
+        }
+        return null;
+    }
+
+    /**
+     * Returns the private key spec class for a given algorithm, or null if it
+     * is not known.
+     */
+    private Class getPublicKeySpecClass(String algName) {
+        if (algName.equals("RSA")) {
+            return java.security.spec.RSAPublicKeySpec.class;
+        }
+        if (algName.equals("DSA")) {
+            return java.security.spec.DSAPublicKeySpec.class;
+        }
+        return null;
+    }
+
+    public class KeyFactoryStub extends KeyFactory {
+        public KeyFactoryStub(KeyFactorySpi keyFacSpi, Provider provider,
+                String algorithm) {
+            super(keyFacSpi, provider, algorithm);
+        }
+    }
+
+    public class KeyFactorySpiStub extends KeyFactorySpi {
+        public KeyFactorySpiStub() {
+            super();
+        }
+        
+        public PrivateKey engineGeneratePrivate(KeySpec keySpec) {
+            return null;
+        }
+
+        public PublicKey engineGeneratePublic(KeySpec keySpec) {
+            return null;
+        }
+
+        public <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec) {
+            return null;
+        }
+
+        public Key engineTranslateKey(Key key) {
+            return null;
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyManagementException2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyManagementException2Test.java
new file mode 100644
index 0000000..4f0dda6
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyManagementException2Test.java
@@ -0,0 +1,45 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.KeyManagementException;
+
+public class KeyManagementException2Test extends junit.framework.TestCase {
+
+    /**
+     * @tests java.security.KeyManagementException#KeyManagementException()
+     */
+    public void test_Constructor() {
+        // Test for method java.security.KeyManagementException()
+        KeyManagementException e = new KeyManagementException();
+        assertEquals("Failed toString test for constructed instance",
+                "java.security.KeyManagementException", e.toString());
+    }
+
+    /**
+     * @tests java.security.KeyManagementException#KeyManagementException(java.lang.String)
+     */
+    public void test_ConstructorLjava_lang_String() {
+        // Test for method
+        // java.security.KeyManagementException(java.lang.String)
+        KeyManagementException e = new KeyManagementException("test message");
+        assertEquals("Failed toString test for constructed instance",
+                "java.security.KeyManagementException: test message",
+                e.toString());
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyManagementExceptionTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyManagementExceptionTest.java
new file mode 100644
index 0000000..7ca3322
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyManagementExceptionTest.java
@@ -0,0 +1,190 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.KeyManagementException;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>KeyManagementException</code> class constructors and
+ * methods.
+ * 
+ */
+public class KeyManagementExceptionTest extends TestCase {
+
+    public static void main(String[] args) {
+    }
+
+    /**
+     * Constructor for KeyManagementExceptionTests.
+     * 
+     * @param arg0
+     */
+    public KeyManagementExceptionTest(String arg0) {
+        super(arg0);
+    }
+
+    private static String[] msgs = {
+            "",
+            "Check new message",
+            "Check new message Check new message Check new message Check new message Check new message" };
+
+    private static Throwable tCause = new Throwable("Throwable for exception");
+
+    /**
+     * Test for <code>KeyManagementException()</code> constructor Assertion:
+     * constructs KeyManagementException with no detail message
+     */
+    public void testKeyManagementException01() {
+        KeyManagementException tE = new KeyManagementException();
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>KeyManagementException(String)</code> constructor
+     * Assertion: constructs KeyManagementException with detail message msg.
+     * Parameter <code>msg</code> is not null.
+     */
+    public void testKeyManagementException02() {
+        KeyManagementException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new KeyManagementException(msgs[i]);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+
+    /**
+     * Test for <code>KeyManagementException(String)</code> constructor
+     * Assertion: constructs KeyManagementException when <code>msg</code> is
+     * null
+     */
+    public void testKeyManagementException03() {
+        String msg = null;
+        KeyManagementException tE = new KeyManagementException(msg);
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>KeyManagementException(Throwable)</code> constructor
+     * Assertion: constructs KeyManagementException when <code>cause</code> is
+     * null
+     */
+    public void testKeyManagementException04() {
+        Throwable cause = null;
+        KeyManagementException tE = new KeyManagementException(cause);
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>KeyManagementException(Throwable)</code> constructor
+     * Assertion: constructs KeyManagementException when <code>cause</code> is
+     * not null
+     */
+    public void testKeyManagementException05() {
+        KeyManagementException tE = new KeyManagementException(tCause);
+        if (tE.getMessage() != null) {
+            String toS = tCause.toString();
+            String getM = tE.getMessage();
+            assertTrue("getMessage() should contain ".concat(toS), (getM
+                    .indexOf(toS) != -1));
+        }
+        assertNotNull("getCause() must not return null", tE.getCause());
+        assertEquals("getCause() must return ".concat(tCause.toString()), tE
+                .getCause(), tCause);
+    }
+
+    /**
+     * Test for <code>KeyManagementException(String, Throwable)</code>
+     * constructor Assertion: constructs KeyManagementException when
+     * <code>cause</code> is null <code>msg</code> is null
+     */
+    public void testKeyManagementException06() {
+        KeyManagementException tE = new KeyManagementException(null, null);
+        assertNull("getMessage() must return null", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>KeyManagementException(String, Throwable)</code>
+     * constructor Assertion: constructs KeyManagementException when
+     * <code>cause</code> is null <code>msg</code> is not null
+     */
+    public void testKeyManagementException07() {
+        KeyManagementException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new KeyManagementException(msgs[i], null);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+
+    /**
+     * Test for <code>KeyManagementException(String, Throwable)</code>
+     * constructor Assertion: constructs KeyManagementException when
+     * <code>cause</code> is not null <code>msg</code> is null
+     */
+    public void testKeyManagementException08() {
+        KeyManagementException tE = new KeyManagementException(null, tCause);
+        if (tE.getMessage() != null) {
+            String toS = tCause.toString();
+            String getM = tE.getMessage();
+            assertTrue("getMessage() must should ".concat(toS), (getM
+                    .indexOf(toS) != -1));
+        }
+        assertNotNull("getCause() must not return null", tE.getCause());
+        assertEquals("getCause() must return ".concat(tCause.toString()), tE
+                .getCause(), tCause);
+    }
+
+    /**
+     * Test for <code>KeyManagementException(String, Throwable)</code>
+     * constructor Assertion: constructs KeyManagementException when
+     * <code>cause</code> is not null <code>msg</code> is not null
+     */
+    public void testKeyManagementException09() {
+        KeyManagementException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new KeyManagementException(msgs[i], tCause);
+            String getM = tE.getMessage();
+            String toS = tCause.toString();
+            if (msgs[i].length() > 0) {
+                assertTrue("getMessage() must contain ".concat(msgs[i]), getM
+                        .indexOf(msgs[i]) != -1);
+                if (!getM.equals(msgs[i])) {
+                    assertTrue("getMessage() should contain ".concat(toS), getM
+                            .indexOf(toS) != -1);
+                }
+            }
+            assertNotNull("getCause() must not return null", tE.getCause());
+            assertEquals("getCause() must return ".concat(tCause.toString()),
+                    tE.getCause(), tCause);
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyPairGenerator1Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyPairGenerator1Test.java
new file mode 100644
index 0000000..c2a9441
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyPairGenerator1Test.java
@@ -0,0 +1,514 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.apache.harmony.security.tests.support.MyKeyPairGenerator1;
+import org.apache.harmony.security.tests.support.MyKeyPairGenerator2;
+import org.apache.harmony.security.tests.support.SpiEngUtils;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>KeyPairGenerator</code> class constructors and methods.
+ * 
+ */
+
+public class KeyPairGenerator1Test extends TestCase {
+
+    /**
+     * Constructor for KayPairGeneratorTest.
+     * 
+     * @param arg0
+     */
+    public KeyPairGenerator1Test(String arg0) {
+        super(arg0);
+    }
+
+    private static String[] invalidValues = SpiEngUtils.invalidValues;
+    
+    public static final String srvKeyPairGenerator = "KeyPairGenerator";
+
+    public static String[] algs = {
+            "DSA", "dsa", "Dsa", "DsA", "dsA" };
+
+    public static String validAlgName = "DSA";
+
+    private static String validProviderName = null;
+
+    public static Provider validProvider = null;
+
+    private static boolean DSASupported = false;
+    
+    public static String NotSupportMsg = "";
+
+    static {
+        validProvider = SpiEngUtils.isSupport(
+                validAlgName,
+                srvKeyPairGenerator);
+        DSASupported = (validProvider != null);
+        if (!DSASupported) {
+            NotSupportMsg = validAlgName + " algorithm is not supported" ;
+        }        
+        validProviderName = (DSASupported ? validProvider.getName() : null);
+    }
+    
+    protected KeyPairGenerator [] createKPGen() {
+        if (!DSASupported) {
+            fail(NotSupportMsg);
+            return null;
+        }
+        KeyPairGenerator[] kpg = new KeyPairGenerator[3];
+        try {
+            kpg[0] = KeyPairGenerator.getInstance(validAlgName);
+            kpg[1] = KeyPairGenerator.getInstance(validAlgName, validProvider);
+            kpg[2] = KeyPairGenerator.getInstance(validAlgName, validProviderName);
+            return kpg;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * Test for <code>getInstance(String algorithm)</code> method 
+     * Assertion:
+     * throws NullPointerException  when algorithm is null
+     * throws NoSuchAlgorithmException when algorithm is incorrect; 
+     */
+    public void testKeyPairGenerator01() throws NoSuchAlgorithmException {
+        try {
+            KeyPairGenerator.getInstance(null);
+            fail("NullPointerException or NoSuchAlgorithmException must be thrown  when algorithm is null");
+        } catch (NoSuchAlgorithmException e) {
+        } catch (NullPointerException e) {
+        }
+        for (int i = 0; i < invalidValues.length; i++) {
+            try {
+                KeyPairGenerator.getInstance(invalidValues[i]);
+                fail("NoSuchAlgorithmException must be thrown when algorithm is not available: "
+                        .concat(invalidValues[i]));
+            } catch (NoSuchAlgorithmException e) {
+            }
+        }
+    }
+
+    /**
+     * Test for <code>getInstance(String algorithm)</code> method 
+     * Assertion: returns KeyPairGenerator object
+     */
+    public void testKeyPairGenerator02() throws NoSuchAlgorithmException {
+        if (!DSASupported) {
+            fail(NotSupportMsg);
+            return;
+        }
+        KeyPairGenerator kpg;
+        for (int i = 0; i < algs.length; i++) {
+            kpg = KeyPairGenerator.getInstance(algs[i]);
+            assertEquals("Incorrect algorithm ", kpg.getAlgorithm().toUpperCase(),
+                    algs[i].toUpperCase());
+        }
+    }
+
+    /**
+     * Test for <code>getInstance(String algorithm, String provider)</code>
+     * method 
+     * Assertion: throws IllegalArgumentException when provider is null or empty
+     */
+    public void testKeyPairGenerator03() throws NoSuchAlgorithmException,
+            NoSuchProviderException {
+        if (!DSASupported) {
+            fail(NotSupportMsg);
+            return;
+        }
+        String provider = null;
+        for (int i = 0; i < algs.length; i++) {
+            try {
+                KeyPairGenerator.getInstance(algs[i], provider);
+                fail("IllegalArgumentException must be thrown when provider is null");
+            } catch (IllegalArgumentException e) {
+            }
+            try {
+                KeyPairGenerator.getInstance(algs[i], "");
+                fail("IllegalArgumentException must be thrown when provider is empty");
+            } catch (IllegalArgumentException e) {
+            }
+        }
+    }
+
+    /**
+     * Test for <code>getInstance(String algorithm, String provider)</code>
+     * method 
+     * Assertion:
+     * throws NullPointerException  when algorithm is null
+     * throws NoSuchAlgorithmException when algorithm is incorrect; 
+     */
+    public void testKeyPairGenerator04() throws NoSuchAlgorithmException,
+            IllegalArgumentException {
+        if (!DSASupported) {
+            fail(NotSupportMsg);
+            return;
+        }
+        for (int i = 0; i < algs.length; i++) {
+            for (int j = 1; j < invalidValues.length; j++) {
+                try {
+                    KeyPairGenerator.getInstance(algs[i], invalidValues[j]);
+                    fail("NoSuchProviderException must be thrown (algorithm: "
+                            .concat(algs[i]).concat(" provider: ").concat(
+                                    invalidValues[j]).concat(")"));
+                } catch (NoSuchProviderException e) {
+                }
+            }
+        }
+    }
+
+    /**
+     * Test for <code>getInstance(String algorithm, String provider)</code>
+     * method 
+     * Assertion: throws NoSuchAlgorithmException when algorithm is not
+     * available oe null
+     */
+    public void testKeyPairGenerator05() throws NoSuchProviderException,
+            IllegalArgumentException {
+        if (!DSASupported) {
+            fail(NotSupportMsg);
+            return;
+        }
+        try {
+            KeyPairGenerator.getInstance(null, validProviderName);
+            fail("NullPointerException or NoSuchAlgorithmException must be thrown  when algorithm is null");
+        } catch (NoSuchAlgorithmException e) {
+        } catch (NullPointerException e) {
+        }
+        for (int i = 0; i < invalidValues.length; i++) {
+            try {
+                KeyPairGenerator.getInstance(invalidValues[i],
+                        validProviderName);
+                fail("NoSuchAlgorithmException must be thrown (algorithm: "
+                        .concat(algs[i]).concat(" provider: ").concat(
+                                validProviderName).concat(")"));
+            } catch (NoSuchAlgorithmException e) {
+            }
+        }
+    }
+
+    /**
+     * Test for <code>getInstance(String algorithm, String provider)</code>
+     * method 
+     * Assertion: returns KeyPairGenerator object
+     */
+    public void testKeyPairGenerator06() throws NoSuchProviderException,
+            NoSuchAlgorithmException, IllegalArgumentException {
+        if (!DSASupported) {
+            fail(NotSupportMsg);
+            return;
+        }
+        KeyPairGenerator kpg;
+        for (int i = 0; i < algs.length; i++) {
+            kpg = KeyPairGenerator.getInstance(algs[i], validProviderName);
+            assertEquals("Incorrect algorithm", kpg.getAlgorithm().toUpperCase(),
+                    algs[i].toUpperCase());
+            assertEquals("Incorrect provider", kpg.getProvider().getName(),
+                    validProviderName);
+        }
+    }
+
+    /**
+     * Test for <code>getInstance(String algorithm, Provider provider)</code>
+     * method 
+     * Assertion: throws IllegalArgumentException when provider is null
+     */
+    public void testKeyPairGenerator07() throws NoSuchAlgorithmException {
+        if (!DSASupported) {
+            fail(NotSupportMsg);
+            return;
+        }
+        Provider provider = null;
+        for (int i = 0; i < algs.length; i++) {
+            try {
+                KeyPairGenerator.getInstance(algs[i], provider);
+                fail("IllegalArgumentException must be thrown when provider is null");
+            } catch (IllegalArgumentException e) {
+            }
+        }
+    }
+
+    /**
+     * Test for <code>getInstance(String algorithm, Provider provider)</code>
+     * method 
+     * Assertion: 
+     * throws NullPointerException  when algorithm is null
+     * throws NoSuchAlgorithmException when algorithm is incorrect; 
+     */
+    public void testKeyPairGenerator08() throws IllegalArgumentException {
+        if (!DSASupported) {
+            fail(NotSupportMsg);
+            return;
+        }
+        try {
+            KeyPairGenerator.getInstance(null, validProvider);
+            fail("NullPointerException or NoSuchAlgorithmException must be thrown  when algorithm is null");
+        } catch (NoSuchAlgorithmException e) {
+        } catch (NullPointerException e) {
+        }
+        for (int i = 0; i < invalidValues.length; i++) {
+            try {
+                KeyPairGenerator.getInstance(invalidValues[i], validProvider);
+                fail("NoSuchAlgorithmException must be thrown (algorithm: "
+                        .concat(algs[i]).concat(" provider: ").concat(
+                                validProviderName).concat(")"));
+            } catch (NoSuchAlgorithmException e) {
+            }
+        }
+    }
+
+    /**
+     * Test for <code>getInstance(String algorithm, Provider provider)</code>
+     * method 
+     * Assertion: returns KeyPairGenerator object
+     */
+    public void testKeyPairGenerator09() throws NoSuchAlgorithmException,
+            IllegalArgumentException {
+        if (!DSASupported) {
+            fail(NotSupportMsg);
+            return;
+        }
+        KeyPairGenerator kpg;
+        for (int i = 0; i < algs.length; i++) {
+            kpg = KeyPairGenerator.getInstance(algs[i], validProvider);
+            assertEquals("Incorrect algorithm", kpg.getAlgorithm().toUpperCase(),
+                    algs[i].toUpperCase());
+            assertEquals("Incorrect provider", kpg.getProvider(), validProvider);
+        }
+    }
+    
+    /**
+     * Test for <code>generateKeyPair()</code> and <code>genKeyPair()</code>
+     * methods
+     * Assertion: KeyPairGenerator was initialized before the invocation 
+     * of these methods
+     */
+    public void testKeyPairGenerator10() throws NoSuchAlgorithmException,
+            NoSuchProviderException, IllegalArgumentException {
+            if (!DSASupported) {
+                fail(NotSupportMsg);
+                return;
+            }
+            KeyPairGenerator[] kpg = createKPGen();
+            assertNotNull("KeyPairGenerator objects were not created", kpg);
+            KeyPair kp, kp1;
+            for (int i = 0; i < kpg.length; i++) {
+                kpg[i].initialize(512);
+                kp = kpg[i].generateKeyPair();
+                kp1 = kpg[i].genKeyPair();
+
+                assertFalse("Incorrect private key", kp.getPrivate().equals(
+                        kp1.getPrivate()));
+                assertFalse("Incorrect public key", kp.getPublic().equals(
+                        kp1.getPublic()));
+            }
+    }
+    
+    /**
+     * Test for methods: 
+     * <code>initialize(int keysize)</code>
+     * <code>initialize(int keysize, SecureRandom random)</code>
+     * <code>initialize(AlgorithmParameterSpec param)</code>
+     * <code>initialize(AlgorithmParameterSpec param, SecureRandom random)</code>
+     * Assertion: throws InvalidParameterException or
+     * InvalidAlgorithmParameterException when parameters keysize or param are
+     * incorrect
+     */   
+    public void testKeyPairGenerator11() throws NoSuchAlgorithmException,
+            NoSuchProviderException {
+        if (!DSASupported) {
+            fail(NotSupportMsg);
+            return;
+        }
+        int[] keys =  { -10000, -1024, -1, 0, 10000 };
+        KeyPairGenerator[] kpg = createKPGen();
+        assertNotNull("KeyPairGenerator objects were not created", kpg);
+        SecureRandom random = new SecureRandom();
+        AlgorithmParameterSpec aps = null;
+
+        for (int i = 0; i < kpg.length; i++) {
+                        
+            for (int j = 0; j < keys.length; j++) {                
+                try {
+                    kpg[i].initialize(keys[j]);
+                    kpg[i].initialize(keys[j], random);
+                } catch (InvalidParameterException e) {
+                }
+            }            
+
+            try {
+                kpg[i].initialize(aps);
+                kpg[i].initialize(aps, random);
+            } catch (InvalidAlgorithmParameterException e) {
+            }
+        }
+    }
+    
+    /**
+     * Test for methods: <code>initialize(int keysize)</code>
+     * <code>initialize(int keysize, SecureRandom random)</code>
+     * <code>initialize(AlgorithmParameterSpec param)</code>
+     * <code>initialize(AlgorithmParameterSpec param, SecureRandom random)</code>
+     * <code>generateKeyPair()</code>
+     * <code>genKeyPair()</code>
+     * Assertion: throws InvalidParameterException or
+     * InvalidAlgorithmParameterException when parameters keysize or param are
+     * incorrect Assertion: generateKeyPair() and genKeyPair() return null
+     * KeyPair Additional class MyKeyPairGenerator1 is used
+     */
+    public void testKeyPairGenerator12() {
+        int[] keys = { -1, -250, 1, 64, 512, 1024 };
+        SecureRandom random = new SecureRandom();
+        AlgorithmParameterSpec aps;
+        KeyPairGenerator mKPG = new MyKeyPairGenerator1("");
+        assertEquals("Incorrect algorithm", mKPG.getAlgorithm(),
+                MyKeyPairGenerator1.getResAlgorithm());
+
+        mKPG.generateKeyPair();
+        mKPG.genKeyPair();
+
+        for (int i = 0; i < keys.length; i++) {
+            try {
+                mKPG.initialize(keys[i]);
+                fail("InvalidParameterException must be thrown (key: "
+                        + Integer.toString(keys[i]) + ")");
+            } catch (InvalidParameterException e) {
+            }
+            try {
+                mKPG.initialize(keys[i], random);
+                fail("InvalidParameterException must be thrown (key: "
+                        + Integer.toString(keys[i]) + ")");
+            } catch (InvalidParameterException e) {
+            }
+        }
+        try {
+            mKPG.initialize(100, null);
+            fail("InvalidParameterException must be thrown when random is null");
+        } catch (InvalidParameterException e) {
+        }
+
+        mKPG.initialize(100, random);
+        assertEquals("Incorrect random", random,
+                ((MyKeyPairGenerator1) mKPG).secureRandom);
+        assertEquals("Incorrect keysize", 100,
+                ((MyKeyPairGenerator1) mKPG).keySize);
+        try {
+            mKPG.initialize(null, random);
+            fail("InvalidAlgorithmParameterException must be thrown when param is null");
+        } catch (InvalidAlgorithmParameterException e) {
+        }
+        if (DSASupported) {
+            BigInteger bInt = new BigInteger("1");
+            aps = new java.security.spec.DSAParameterSpec(bInt, bInt, bInt);
+            try {
+                mKPG.initialize(aps, null);
+                fail("InvalidParameterException must be thrown when random is null");
+            } catch (InvalidParameterException e) {
+            } catch (InvalidAlgorithmParameterException e) {
+                fail("Unexpected InvalidAlgorithmParameterException was thrown");
+            }
+            try {
+                mKPG.initialize(aps, random);
+                assertEquals("Incorrect random", random,
+                        ((MyKeyPairGenerator1) mKPG).secureRandom);
+                assertEquals("Incorrect params", aps,
+                        ((MyKeyPairGenerator1) mKPG).paramSpec);
+            } catch (InvalidAlgorithmParameterException e) {
+                fail("Unexpected InvalidAlgorithmParameterException was thrown");
+            }
+        }
+    }
+    
+    /**
+     * Test for methods: <code>initialize(int keysize)</code>
+     * <code>initialize(int keysize, SecureRandom random)</code>
+     * <code>initialize(AlgorithmParameterSpec param)</code>
+     * <code>initialize(AlgorithmParameterSpec param, SecureRandom random)</code>
+     * <code>generateKeyPair()</code>
+     * <code>genKeyPair()</code>
+     * Assertion: initialize(int ...) throws InvalidParameterException when
+     * keysize in incorrect Assertion: initialize(AlgorithmParameterSpec
+     * ...)throws UnsupportedOperationException Assertion: generateKeyPair() and
+     * genKeyPair() return not null KeyPair Additional class MyKeyPairGenerator2
+     * is used
+     */
+    public void testKeyPairGenerator13() {
+        int[] keys = { -1, -250, 1, 63, -512, -1024 };
+        SecureRandom random = new SecureRandom();
+        KeyPairGenerator mKPG = new MyKeyPairGenerator2(null);
+        assertEquals("Algorithm must be null", mKPG.getAlgorithm(),
+                MyKeyPairGenerator2.getResAlgorithm());
+        assertNull("genKeyPair() must return null", mKPG.genKeyPair());
+        assertNull("generateKeyPair() mut return null", mKPG.generateKeyPair());
+        for (int i = 0; i < keys.length; i++) {
+            try {
+                mKPG.initialize(keys[i]);
+                fail("InvalidParameterException must be thrown (key: "
+                        + Integer.toString(keys[i]) + ")");
+            } catch (InvalidParameterException e) {
+            }
+            try {
+                mKPG.initialize(keys[i], random);
+                fail("InvalidParameterException must be thrown (key: "
+                        + Integer.toString(keys[i]) + ")");
+            } catch (InvalidParameterException e) {
+            }
+        }
+        try {
+            mKPG.initialize(64);
+        } catch (InvalidParameterException e) {
+            fail("Unexpected InvalidParameterException was thrown");
+        }
+        try {
+            mKPG.initialize(64, null);
+        } catch (InvalidParameterException e) {
+            fail("Unexpected InvalidParameterException was thrown");
+        }
+        try {
+            mKPG.initialize(null, random);
+        } catch (UnsupportedOperationException e) {
+            // on j2se1.4 this exception is not thrown
+        } catch (InvalidAlgorithmParameterException e) {
+            fail("Unexpected InvalidAlgorithmParameterException was thrown");
+        }
+    }
+
+    public static void main(String args[]) {
+        junit.textui.TestRunner.run(KeyPairGenerator1Test.class);
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyPairGenerator2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyPairGenerator2Test.java
new file mode 100644
index 0000000..881a468
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyPairGenerator2Test.java
@@ -0,0 +1,443 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.apache.harmony.security.tests.support.MyKeyPairGenerator1;
+import org.apache.harmony.security.tests.support.MyKeyPairGenerator2;
+import org.apache.harmony.security.tests.support.SpiEngUtils;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>KeyPairGenerator</code> class constructors and methods.
+ * 
+ */
+
+public class KeyPairGenerator2Test extends TestCase {
+    private String KeyPairGeneratorProviderClass = "";
+
+    private static final String KeyPairGeneratorProviderClass1 = "org.apache.harmony.security.tests.support.MyKeyPairGenerator1";
+    private static final String KeyPairGeneratorProviderClass2 = "org.apache.harmony.security.tests.support.MyKeyPairGenerator2";
+    private static final String KeyPairGeneratorProviderClass3 = "org.apache.harmony.security.tests.support.MyKeyPairGenerator3";
+    private static final String KeyPairGeneratorProviderClass4 = "org.apache.harmony.security.tests.support.MyKeyPairGeneratorSpi";
+    
+    private static final String defaultAlg = "KPGen";
+
+    private static final String[] invalidValues = SpiEngUtils.invalidValues;
+
+    private static final String[] validValues;
+
+    String post;
+    
+    static {
+        validValues = new String[4];
+        validValues[0] = defaultAlg;
+        validValues[1] = defaultAlg.toLowerCase();
+        validValues[2] = "kpGEN";
+        validValues[3] = "kPGEn";
+    }
+
+    Provider mProv; 
+    String resAlg;
+
+    /*
+     * @see TestCase#tearDown()
+     */
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        Security.removeProvider(mProv.getName());
+    }
+
+    protected void setProv() {
+        mProv = (new SpiEngUtils()).new MyProvider("MyKPGenProvider".concat(post),
+                "Testing provider", KeyPairGenerator1Test.srvKeyPairGenerator.concat(".")
+                        .concat(defaultAlg.concat(post)),
+                KeyPairGeneratorProviderClass);
+        Security.insertProviderAt(mProv, 1);
+    }
+
+    /**
+     * Constructor for SecurityManagerFactoryTest2.
+     * 
+     * @param arg0
+     */
+    public KeyPairGenerator2Test(String arg0) {
+        super(arg0);
+    }
+
+    private void checkResult(KeyPairGenerator keyPairGen, int mode)
+            throws InvalidAlgorithmParameterException {
+        AlgorithmParameterSpec pp = null;
+        switch (mode) {
+        case 1:
+            try {
+                keyPairGen.initialize(pp, new SecureRandom());
+                fail("InvalidAlgorithmParameterException must be thrown");
+            } catch (InvalidAlgorithmParameterException e) {
+            }
+            keyPairGen.initialize(1000, new SecureRandom());
+            try {
+                keyPairGen.initialize(-1024, new SecureRandom());
+                fail("InvalidParameterException must be thrown");
+            } catch (InvalidParameterException e) {
+                assertEquals("Incorrect exception", e.getMessage(),
+                        "Incorrect keysize parameter");
+            }
+            try {
+                keyPairGen.initialize(100, null);
+                fail("InvalidParameterException must be thrown");
+            } catch (InvalidParameterException e) {
+                assertEquals("Incorrect exception", e.getMessage(),
+                        "Incorrect random");
+            }
+            keyPairGen.generateKeyPair();
+            keyPairGen.genKeyPair();
+            break;
+        case 2:
+            try {
+                keyPairGen.initialize(pp, new SecureRandom());
+            } catch (UnsupportedOperationException e) {
+                // js2e does not throw this exception
+            }
+            keyPairGen.initialize(1000, new SecureRandom());
+            try {
+                keyPairGen.initialize(63, new SecureRandom());
+                fail("InvalidParameterException must be thrown");
+            } catch (InvalidParameterException e) {
+            }
+            keyPairGen.initialize(100, null);
+            assertNull("Not null KeyPair", keyPairGen.generateKeyPair());
+            assertNull("Not null KeyPair", keyPairGen.genKeyPair());
+            break;
+        case 3:
+            keyPairGen.initialize(pp, new SecureRandom());
+            keyPairGen.initialize(pp);
+            keyPairGen.initialize(1000, new SecureRandom());
+            keyPairGen.initialize(100);
+
+            assertNotNull("Null KeyPair", keyPairGen.generateKeyPair());
+            assertNotNull("Null KeyPair", keyPairGen.genKeyPair());
+            break;
+        case 4:
+            try {
+                keyPairGen.initialize(pp, null);
+                fail("UnsupportedOperationException must be thrown");
+            } catch (UnsupportedOperationException e) {
+            }
+            keyPairGen.initialize(pp, new SecureRandom());
+            keyPairGen.initialize(101, new SecureRandom());
+            keyPairGen.initialize(10000);
+            try {
+                keyPairGen.initialize(101, null);
+                fail("IllegalArgumentException must be thrown for null random");
+            } catch (IllegalArgumentException e) {
+            }
+            try {
+                keyPairGen.initialize(99, new SecureRandom());
+                fail("InvalidParameterException must be thrown for invalid key");
+            } catch (InvalidParameterException e) {
+            }
+            try {
+                keyPairGen.initialize(99);
+                fail("InvalidParameterException must be thrown for invalid key");
+            } catch (InvalidParameterException e) {
+            }
+            try {
+                keyPairGen.initialize(199, null);
+                fail("IllegalArgumentException must be thrown for null random");
+            } catch (IllegalArgumentException e) {
+            }
+            assertNull("Not null KeyPair", keyPairGen.generateKeyPair());
+            assertNull("Not null KeyPair", keyPairGen.genKeyPair());
+            break;
+        }
+
+    }
+
+    /**
+     * Test for <code>getInstance(String algorithm)</code> method Assertions:
+     * throws NullPointerException when algorithm is null throws
+     * NoSuchAlgorithmException when algorithm is incorrect; returns
+     * KeyPairGenerator object
+     *  
+     */
+    private void GetInstance01(int mode) throws NoSuchAlgorithmException,
+            InvalidAlgorithmParameterException {
+        try {
+            KeyPairGenerator.getInstance(null);
+            fail("NullPointerException or KeyStoreException must be thrown");
+        } catch (NoSuchAlgorithmException e) {
+        } catch (NullPointerException e) {
+        }
+        for (int i = 0; i < invalidValues.length; i++) {
+            try {
+                KeyPairGenerator.getInstance(invalidValues[i]);
+                fail("NoSuchAlgorithmException must be thrown (algorithm: "
+                        .concat(invalidValues[i]).concat(")"));
+            } catch (NoSuchAlgorithmException e) {
+            }
+        }
+        KeyPairGenerator kpG;
+        for (int i = 0; i < validValues.length; i++) {
+            String alg = validValues[i].concat(post);
+            kpG = KeyPairGenerator.getInstance(alg);
+            assertEquals("Incorrect algorithm", kpG.getAlgorithm()
+                    .toUpperCase(), (mode <= 2 ? resAlg : alg).toUpperCase());
+            assertEquals("Incorrect provider", kpG.getProvider(), mProv);
+            checkResult(kpG, mode);
+        }
+    }
+
+    /**
+     * Test for <code>getInstance(String algorithm, String provider)</code>
+     * method 
+     * Assertions: 
+     * throws NullPointerException  when algorithm is null
+     * throws NoSuchAlgorithmException when algorithm is incorrect; 
+     * throws IllegalArgumentException when provider is null;
+     * throws NoSuchProviderException when provider is available; 
+     * returns
+     * KeyPairGenerator object
+     */
+    public void GetInstance02(int mode) throws NoSuchAlgorithmException,
+            NoSuchProviderException, IllegalArgumentException,
+            InvalidAlgorithmParameterException {
+        try {
+            KeyPairGenerator.getInstance(null, mProv.getName());
+            fail("NullPointerException or KeyStoreException must be thrown");
+        } catch (NoSuchAlgorithmException e) {
+        } catch (NullPointerException e) {
+        }
+        for (int i = 0; i < invalidValues.length; i++) {
+            try {
+                KeyPairGenerator.getInstance(invalidValues[i], mProv.getName());
+                fail("NoSuchAlgorithmException must be thrown (algorithm: "
+                        .concat(invalidValues[i]).concat(")"));
+            } catch (NoSuchAlgorithmException e) {
+            }
+        }
+        String prov = null;
+        for (int i = 0; i < validValues.length; i++) {
+            String alg = validValues[i].concat(post);
+            try {
+                KeyPairGenerator.getInstance(alg, prov);
+                fail("IllegalArgumentException must be thrown when provider is null (algorithm: "
+                        .concat(alg).concat(")"));
+            } catch (IllegalArgumentException e) {
+            }
+        }
+        for (int i = 0; i < validValues.length; i++) {
+            String alg = validValues[i].concat(post);
+            for (int j = 1; j < invalidValues.length; j++) {
+                try {
+                    KeyPairGenerator.getInstance(alg, invalidValues[j]);
+                    fail("NoSuchProviderException must be thrown (algorithm: "
+                            .concat(alg).concat(" provider: ").concat(
+                                    invalidValues[j]).concat(")"));
+                } catch (NoSuchProviderException e) {
+                }
+            }
+        }
+        KeyPairGenerator kpG;
+        for (int i = 0; i < validValues.length; i++) {
+            String alg = validValues[i].concat(post);
+            kpG = KeyPairGenerator.getInstance(alg, mProv.getName());
+            assertEquals("Incorrect algorithm", kpG.getAlgorithm()
+                    .toUpperCase(), (mode <= 2 ? resAlg : alg).toUpperCase());
+            assertEquals("Incorrect provider", kpG.getProvider().getName(),
+                    mProv.getName());
+            checkResult(kpG, mode);
+        }
+    }
+
+    /**
+     * Test for <code>getInstance(String algorithm, Provider provider)</code>
+     * method 
+     * Assertions: 
+     * throws NullPointerException  when algorithm is null
+     * throws NoSuchAlgorithmException when algorithm is incorrect; 
+     * throws IllegalArgumentException when provider is null;
+     * returns KeyPairGenerator object
+     */
+    private void GetInstance03(int mode) throws NoSuchAlgorithmException,
+            IllegalArgumentException, InvalidAlgorithmParameterException {
+        try {
+            KeyPairGenerator.getInstance(null, mProv);
+            fail("NullPointerException or KeyStoreException must be thrown");
+        } catch (NoSuchAlgorithmException e) {
+        } catch (NullPointerException e) {
+        }
+        for (int i = 0; i < invalidValues.length; i++) {
+            try {
+                KeyPairGenerator.getInstance(invalidValues[i], mProv);
+                fail("NoSuchAlgorithmException must be thrown (algorithm: "
+                        .concat(invalidValues[i]).concat(")"));
+            } catch (NoSuchAlgorithmException e) {
+            }
+        }
+        Provider prov = null;
+        for (int i = 0; i < validValues.length; i++) {
+            String alg = validValues[i].concat(post);
+            try {
+                KeyPairGenerator.getInstance(alg, prov);
+                fail("IllegalArgumentException must be thrown when provider is null (algorithm: "
+                        .concat(alg).concat(")"));
+            } catch (IllegalArgumentException e) {
+            }
+        }
+        KeyPairGenerator kpG;
+        for (int i = 0; i < validValues.length; i++) {
+            String alg = validValues[i].concat(post);
+            kpG = KeyPairGenerator.getInstance(alg, mProv);
+            assertEquals("Incorrect algorithm", kpG.getAlgorithm()
+                    .toUpperCase(), (mode <= 2 ? resAlg : alg).toUpperCase());
+            assertEquals("Incorrect provider", kpG.getProvider(), mProv);
+            checkResult(kpG, mode);
+        }
+    }
+
+    public void testGetInstance01() throws NoSuchAlgorithmException,
+            InvalidAlgorithmParameterException {
+        KeyPairGeneratorProviderClass = KeyPairGeneratorProviderClass1;
+        resAlg = MyKeyPairGenerator1.getResAlgorithm();
+        post = "_1";
+        setProv();
+        GetInstance01(1);
+    }
+
+    public void testGetInstance02() throws NoSuchAlgorithmException,
+            NoSuchProviderException, IllegalArgumentException,
+            InvalidAlgorithmParameterException {
+        KeyPairGeneratorProviderClass = KeyPairGeneratorProviderClass1;
+        resAlg = MyKeyPairGenerator1.getResAlgorithm();
+        post = "_1";
+        setProv();
+        GetInstance02(1);
+    }
+
+    public void testGetInstance03() throws NoSuchAlgorithmException,
+            IllegalArgumentException, InvalidAlgorithmParameterException {
+        KeyPairGeneratorProviderClass = KeyPairGeneratorProviderClass1;
+        resAlg = MyKeyPairGenerator1.getResAlgorithm();
+        post = "_1";
+        setProv();
+        GetInstance03(1);
+    }
+
+    public void testGetInstance04() throws NoSuchAlgorithmException,
+            InvalidAlgorithmParameterException {
+        KeyPairGeneratorProviderClass = KeyPairGeneratorProviderClass2;
+        resAlg = MyKeyPairGenerator2.getResAlgorithm();
+        post = "_2";
+        setProv();
+        GetInstance01(2);
+    }
+
+    public void testGetInstance05() throws NoSuchAlgorithmException,
+            NoSuchProviderException, IllegalArgumentException,
+            InvalidAlgorithmParameterException {
+        KeyPairGeneratorProviderClass = KeyPairGeneratorProviderClass2;
+        resAlg = MyKeyPairGenerator2.getResAlgorithm();
+        post = "_2";
+        setProv();
+        GetInstance02(2);
+    }
+
+    public void testGetInstance06() throws NoSuchAlgorithmException,
+            IllegalArgumentException, InvalidAlgorithmParameterException {
+        KeyPairGeneratorProviderClass = KeyPairGeneratorProviderClass2;
+        resAlg = MyKeyPairGenerator2.getResAlgorithm();
+        post = "_2";
+        setProv();
+        GetInstance03(2);
+    }
+
+    public void testGetInstance07() throws NoSuchAlgorithmException,
+            InvalidAlgorithmParameterException {
+        KeyPairGeneratorProviderClass = KeyPairGeneratorProviderClass3;
+        resAlg = "";
+        post = "_3";
+        setProv();
+        GetInstance01(3);
+    }
+
+    public void testGetInstance08() throws NoSuchAlgorithmException,
+            NoSuchProviderException, IllegalArgumentException,
+            InvalidAlgorithmParameterException {
+        KeyPairGeneratorProviderClass = KeyPairGeneratorProviderClass3;
+        resAlg = "";
+        post = "_3";
+        setProv();
+        GetInstance02(3);
+    }
+
+    public void testGetInstance09() throws NoSuchAlgorithmException,
+            IllegalArgumentException, InvalidAlgorithmParameterException {
+        KeyPairGeneratorProviderClass = KeyPairGeneratorProviderClass3;
+        resAlg = "";
+        post = "_3";
+        setProv();
+        GetInstance03(3);
+    }
+
+    public void testGetInstance10() throws NoSuchAlgorithmException,
+            InvalidAlgorithmParameterException {
+        KeyPairGeneratorProviderClass = KeyPairGeneratorProviderClass4;
+        resAlg = "";
+        post = "_4";
+        setProv();
+        GetInstance01(4);
+    }
+
+    public void testGetInstance11() throws NoSuchAlgorithmException,
+            NoSuchProviderException, IllegalArgumentException,
+            InvalidAlgorithmParameterException {
+        KeyPairGeneratorProviderClass = KeyPairGeneratorProviderClass4;
+        resAlg = "";
+        post = "_4";
+        setProv();
+        GetInstance02(4);
+    }
+
+    public void testGetInstance12() throws NoSuchAlgorithmException,
+            IllegalArgumentException, InvalidAlgorithmParameterException {
+        KeyPairGeneratorProviderClass = KeyPairGeneratorProviderClass4;
+        resAlg = "";
+        post = "_4";
+        setProv();
+        GetInstance03(4);
+    }
+    public static void main(String args[]) {
+        junit.textui.TestRunner.run(KeyPairGenerator2Test.class);
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyPairGenerator3Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyPairGenerator3Test.java
new file mode 100644
index 0000000..c898207
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyPairGenerator3Test.java
@@ -0,0 +1,145 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.SecureRandom;
+
+import org.apache.harmony.security.tests.support.SpiEngUtils;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for KeyPairGenerator class
+ * 
+ */
+
+public class KeyPairGenerator3Test extends TestCase {
+
+    /**
+     * Constructor for KeyPairGenerator3Test.
+     * 
+     * @param arg0
+     */
+    public KeyPairGenerator3Test(String arg0) {
+        super(arg0);
+    }
+
+    private static String validProviderName = null;
+
+    public static Provider validProvider = null;
+
+    private static boolean DSASupported = false;
+    
+    private static String NotSupportMsg = KeyPairGenerator1Test.NotSupportMsg;
+
+    static {
+        validProvider = SpiEngUtils.isSupport(
+                KeyPairGenerator1Test.validAlgName,
+                KeyPairGenerator1Test.srvKeyPairGenerator);
+        DSASupported = (validProvider != null);
+        validProviderName = (DSASupported ? validProvider.getName() : null);
+    }
+
+    protected KeyPairGenerator[] createKPGen() {
+        if (!DSASupported) {
+            fail(KeyPairGenerator1Test.validAlgName
+                    + " algorithm is not supported");
+            return null;
+        }
+        KeyPairGenerator[] kpg = new KeyPairGenerator[3];
+        try {
+            kpg[0] = KeyPairGenerator
+                    .getInstance(KeyPairGenerator1Test.validAlgName);
+            kpg[1] = KeyPairGenerator.getInstance(
+                    KeyPairGenerator1Test.validAlgName, validProvider);
+            kpg[2] = KeyPairGenerator.getInstance(
+                    KeyPairGenerator1Test.validAlgName, validProviderName);
+            return kpg;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    
+    /**
+     * Test for <code>generateKeyPair()</code> and <code>genKeyPair()</code>
+     * methods
+     * Assertion: KeyPairGenerator was initialized before the invocation 
+     * of these methods
+     */
+    public void testGenKeyPair01() throws NoSuchAlgorithmException,
+            NoSuchProviderException, IllegalArgumentException {
+        if (!DSASupported) {
+            fail(NotSupportMsg);
+            return;
+        }
+        KeyPairGenerator[] kpg = createKPGen();
+        assertNotNull("KeyPairGenerator objects were not created", kpg);
+        KeyPair kp, kp1;
+        SecureRandom rr = new SecureRandom();
+        for (int i = 0; i < kpg.length; i++) {
+            kpg[i].initialize(512, rr);
+            kp = kpg[i].generateKeyPair();
+            kp1 = kpg[i].genKeyPair();
+            assertFalse("Incorrect private key", kp.getPrivate().equals(
+                    kp1.getPrivate()));
+            assertFalse("Incorrect public key", kp.getPublic().equals(
+                    kp1.getPublic()));
+        }
+    }
+    
+    /**
+     * Test for <code>generateKeyPair()</code> and <code>genKeyPair()</code>
+     * methods
+     * Assertion: these methods are used without previously initialization
+     */
+    public void testGenKeyPair02() throws NoSuchAlgorithmException,
+            NoSuchProviderException, IllegalArgumentException {
+        if (!DSASupported) {
+            fail(NotSupportMsg);
+            return;
+        }
+        KeyPairGenerator[] kpg = createKPGen();
+        assertNotNull("KeyPairGenerator objects were not created", kpg);
+        KeyPair kp, kp1;   
+        for (int i = 0; i < kpg.length; i++) {
+            kp = kpg[i].generateKeyPair();
+            kp1 = kpg[i].genKeyPair();
+            assertFalse("Incorrect private key", kp.getPrivate().equals(
+                kp1.getPrivate()));
+            assertFalse("Incorrect public key", kp.getPublic().equals(
+                kp1.getPublic()));
+        }
+    }
+
+    public static void main(String args[]) {
+        junit.textui.TestRunner.run(KeyPairGenerator3Test.class);
+    }
+    
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyPairGenerator4Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyPairGenerator4Test.java
new file mode 100644
index 0000000..7ab4564
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyPairGenerator4Test.java
@@ -0,0 +1,138 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.KeyPairGenerator;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.spec.DSAParameterSpec;
+import java.security.interfaces.DSAPublicKey;
+import java.security.interfaces.DSAParams;
+
+public class KeyPairGenerator4Test extends junit.framework.TestCase {
+
+    /**
+     * @tests java.security.KeyPairGenerator#genKeyPair()
+     */
+    public void test_genKeyPair() throws Exception {
+        KeyPairGenerator gen = KeyPairGenerator.getInstance("DSA");
+        gen.initialize(1024);
+        assertNotNull("KeyPair is null", gen.genKeyPair());
+    }
+
+    /**
+     * @tests java.security.KeyPairGenerator#getAlgorithm()
+     */
+    public void test_getAlgorithm() throws Exception {
+        String alg = KeyPairGenerator.getInstance("DSA").getAlgorithm();
+        assertEquals("getAlgorithm returned unexpected value", "DSA", alg);
+    }
+
+    /**
+     * @tests java.security.KeyPairGenerator#getInstance(java.lang.String)
+     */
+    public void test_getInstanceLjava_lang_String() throws Exception {
+        KeyPairGenerator.getInstance("DSA");
+    }
+
+    /**
+     * @tests java.security.KeyPairGenerator#getInstance(java.lang.String,
+     *        java.lang.String)
+     */
+    public void test_getInstanceLjava_lang_StringLjava_lang_String()
+            throws Exception {
+
+        // Test1: Test with named provider
+        Provider[] providers = Security.getProviders("KeyPairGenerator.DSA");
+
+        for (int i = 0; i < providers.length; i++) {
+            KeyPairGenerator.getInstance("DSA", providers[i].getName());
+        }// end for
+
+        // Test2: Test with empty provider name - should raise
+        // IllegalArgumentException
+        try {
+            KeyPairGenerator.getInstance("DSA", "");
+            fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    /**
+     * @tests java.security.KeyPairGenerator#getProvider()
+     */
+    public void test_getProvider() throws Exception {
+        Provider p = KeyPairGenerator.getInstance("DSA").getProvider();
+        assertNotNull("provider is null", p);
+    }
+
+    /**
+     * @tests java.security.KeyPairGenerator#initialize(int)
+     */
+    public void test_initializeI() throws Exception {
+        KeyPairGenerator keyPair = KeyPairGenerator.getInstance("DSA");
+        keyPair.initialize(1024);
+    }
+
+    /**
+     * @tests java.security.KeyPairGenerator#initialize(int,
+     *        java.security.SecureRandom)
+     */
+    public void test_initializeILjava_security_SecureRandom() throws Exception {
+        KeyPairGenerator keyPair = KeyPairGenerator.getInstance("DSA");
+        keyPair.initialize(1024, new SecureRandom());
+    }
+
+
+    /**
+     * @tests java.security.KeyPairGenerator#initialize(java.security.spec.AlgorithmParameterSpec)
+     */
+    public void test_initializeLjava_security_spec_AlgorithmParameterSpec()
+            throws Exception {
+        // create DSAParams
+        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");
+        keyPairGenerator.initialize(1024);
+        DSAPublicKey key = (DSAPublicKey) keyPairGenerator.genKeyPair()
+                .getPublic();
+        DSAParams params = key.getParams();
+
+        KeyPairGenerator keyPair = KeyPairGenerator.getInstance("DSA");
+        keyPair.initialize(new DSAParameterSpec(params.getP(), params.getQ(),
+                params.getG()));
+    }
+
+    /**
+     * @tests java.security.KeyPairGenerator#initialize(java.security.spec.AlgorithmParameterSpec,
+     *        java.security.SecureRandom)
+     */
+    public void test_initializeLjava_security_spec_AlgorithmParameterSpecLjava_security_SecureRandom()
+            throws Exception {
+        // create DSAParams
+        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");
+        keyPairGenerator.initialize(1024);
+        DSAPublicKey key = (DSAPublicKey) keyPairGenerator.genKeyPair()
+                .getPublic();
+        DSAParams params = key.getParams();
+
+        KeyPairGenerator keyPair = KeyPairGenerator.getInstance("DSA");
+        keyPair.initialize(new DSAParameterSpec(params.getP(), params.getQ(),
+                params.getG()), new SecureRandom());
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyPairGeneratorSpiTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyPairGeneratorSpiTest.java
new file mode 100644
index 0000000..bc7b9b5
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyPairGeneratorSpiTest.java
@@ -0,0 +1,88 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGeneratorSpi;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.apache.harmony.security.tests.support.MyKeyPairGeneratorSpi;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>KeyPairGeneratorSpi</code> class constructors and methods.
+ * 
+ */
+
+public class KeyPairGeneratorSpiTest extends TestCase {
+
+    /**
+     * Constructor for KeyPairGeneratorSpiTest.
+     * 
+     * @param arg0
+     */
+    public KeyPairGeneratorSpiTest(String arg0) {
+        super(arg0);
+    }
+
+    /**
+     * Test for <code>KeyPairGeneratorSpi</code> constructor 
+     * Assertion: constructs KeyPairGeneratorSpi
+     */
+    public void testKeyPairGeneratorSpi01()
+            throws InvalidAlgorithmParameterException,
+            InvalidParameterException {
+        KeyPairGeneratorSpi keyPairGen = new MyKeyPairGeneratorSpi();
+
+        AlgorithmParameterSpec pp = null;
+        try {
+            keyPairGen.initialize(pp, null);
+            fail("UnsupportedOperationException must be thrown");
+        } catch (UnsupportedOperationException e) {
+        }
+        keyPairGen.initialize(pp, new SecureRandom());
+        keyPairGen.initialize(1024, new SecureRandom());
+        try {
+            keyPairGen.initialize(-1024, new SecureRandom());
+            fail("IllegalArgumentException must be thrown for incorrect keysize");
+        } catch (IllegalArgumentException e) {
+        }
+        try {
+            keyPairGen.initialize(1024, null);
+            fail("IllegalArgumentException must be thrown");
+        } catch (IllegalArgumentException e) {
+            assertEquals("Incorrect exception", e.getMessage(),
+                    "Invalid random");
+        }
+        KeyPair kp = keyPairGen.generateKeyPair();
+        assertNull("Not null KeyPair", kp);
+    }
+    public static void main(String args[]) {
+        junit.textui.TestRunner.run(KeyPairGeneratorSpiTest.class);
+    }
+
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyPairTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyPairTest.java
new file mode 100644
index 0000000..8864835
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyPairTest.java
@@ -0,0 +1,136 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vladimir N. Molotkov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for fields and methods of class <code>KeyPair</code>
+ * 
+ */
+public class KeyPairTest extends TestCase {
+
+    private static class TestKeyPair {
+        static PublicKey getPublic() {
+            return new PublicKey() {
+                public String getAlgorithm() {
+                    return "never mind";
+                }
+                public String getFormat() {
+                    return "never mind";
+                }
+                public byte[] getEncoded() {
+                    return null;
+                }                
+            };
+        }
+        static PrivateKey getPrivate() {
+            return new PrivateKey() {
+                public String getAlgorithm() {
+                    return "never mind";
+                }
+                public String getFormat() {
+                    return "never mind";
+                }
+                public byte[] getEncoded() {
+                    return null;
+                }                
+            };                
+        }
+    }
+
+    /**
+     * Constructor for KeyPairTest.
+     * @param name
+     */
+    public KeyPairTest(String name) {
+        super(name);
+    }
+
+    /**
+     * Test #1 for <code>KeyPair(PublicKey, PrivateKey)</code> constructor<br>
+     * Assertion: creates new <code>KeyPair</code> instance using valid
+     * parameters (both <code>null</code>)
+     */
+    public final void testKeyPair01() {
+        Object kp = new KeyPair(null, null);
+        assertTrue(kp instanceof KeyPair);
+    }
+
+    /**
+     * Test #2 for <code>KeyPair(PublicKey, PrivateKey)</code> constructor<br>
+     * Assertion: creates new <code>KeyPair</code> instance using valid
+     * parameters (both valid keys)
+     * @throws InvalidKeySpecException
+     */
+    public final void testKeyPair02() throws InvalidKeySpecException {
+        Object kp = new KeyPair(TestKeyPair.getPublic(), TestKeyPair.getPrivate());
+        assertTrue(kp instanceof KeyPair);
+    }
+
+    /**
+     * Test #1 for <code>getPrivate()</code> method<br>
+     * Assertion: returns private key (<code>null</code> in this case)
+     */
+    public final void testGetPrivate01() {
+        KeyPair kp = new KeyPair(null, null);
+        assertNull(kp.getPrivate());
+    }
+
+    /**
+     * Test #2 for <code>getPrivate()</code> method<br>
+     * Assertion: returns private key (valid private key in this case)
+     * @throws InvalidKeySpecException
+     */
+    public final void testGetPrivate02() throws InvalidKeySpecException {
+        PrivateKey pk = TestKeyPair.getPrivate();
+        KeyPair kp = new KeyPair(null, pk);
+        assertSame(pk, kp.getPrivate());
+    }
+
+    /**
+     * Test #1 for <code>getPublic()</code> method<br>
+     * Assertion: returns public key (<code>null</code> in this case)
+     */
+    public final void testGetPublic01() {
+        KeyPair kp = new KeyPair(null, null);
+        assertNull(kp.getPublic());
+    }
+
+    /**
+     * Test #2 for <code>getPublic()</code> method<br>
+     * Assertion: returns public key (valid public key in this case)
+     * @throws InvalidKeySpecException
+     */
+    public final void testGetPublic02() throws InvalidKeySpecException {
+        PublicKey pk = TestKeyPair.getPublic();
+        KeyPair kp = new KeyPair(pk, null);
+        assertSame(pk, kp.getPublic());
+    }
+
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyRepTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyRepTest.java
new file mode 100644
index 0000000..e9081ad
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyRepTest.java
@@ -0,0 +1,228 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Vladimir N. Molotkov
+ * @version $Revision$
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.io.NotSerializableException;
+import java.io.ObjectStreamException;
+import java.security.KeyRep;
+import java.security.Security;
+import java.util.Iterator;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+/**
+ * 
+ * 
+ */
+public class KeyRepTest extends TestCase {
+
+    private static final Set<String> keyFactoryAlgorithm;
+    static {
+        keyFactoryAlgorithm = Security.getAlgorithms("KeyFactory");
+    }
+
+    public final void testKeyRep01() {
+        try {
+            assertNotNull(new KeyRep(KeyRep.Type.SECRET, "", "", new byte[] {}));
+        } catch (Exception e) {
+            fail("Unexpected exception " + e.getMessage());
+        }
+        
+        try {
+            assertNotNull(new KeyRep(KeyRep.Type.PUBLIC, "", "", new byte[] {}));
+        } catch (Exception e) {
+            fail("Unexpected exception " + e.getMessage());
+        }
+        
+        try {
+            assertNotNull(new KeyRep(KeyRep.Type.PRIVATE, "", "", new byte[] {}));
+        } catch (Exception e) {
+            fail("Unexpected exception " + e.getMessage());
+        }
+    }
+
+    public final void testKeyRep02() {
+        try {
+            new KeyRep(null, "", "", new byte[] {});
+            fail("NullPointerException has not been thrown (type)");
+        } catch (NullPointerException ok) {
+
+        }
+        try {
+            new KeyRep(KeyRep.Type.SECRET, null, "", new byte[] {});
+            fail("NullPointerException has not been thrown (alg)");
+        } catch (NullPointerException ok) {
+
+        }
+        try {
+            new KeyRep(KeyRep.Type.PRIVATE, "", null, new byte[] {});
+            fail("NullPointerException has not been thrown (format)");
+        } catch (NullPointerException ok) {
+
+        }
+        try {
+            new KeyRep(KeyRep.Type.PUBLIC, "", "", null);
+            fail("NullPointerException has not been thrown (encoding)");
+        } catch (NullPointerException ok) {
+
+        }
+    }
+
+    public final void testReadResolve01() throws ObjectStreamException {
+        KeyRepChild kr = new KeyRepChild(KeyRep.Type.SECRET, "", "",
+                new byte[] {});
+        try {
+            kr.readResolve();
+            fail("NotSerializableException has not been thrown (no format)");
+        } catch (NotSerializableException ok) {
+
+        }
+
+        kr = new KeyRepChild(KeyRep.Type.SECRET, "", "X.509", new byte[] {});
+        try {
+            kr.readResolve();
+            fail("NotSerializableException has not been thrown (unacceptable format)");
+        } catch (NotSerializableException ok) {
+
+        }
+
+        kr = new KeyRepChild(KeyRep.Type.SECRET, "", "RAW", new byte[] {});
+        try {
+            kr.readResolve();
+            fail("NotSerializableException has not been thrown (empty key)");
+        } catch (NotSerializableException ok) {
+
+        }
+    }
+
+    public final void testReadResolve02() throws ObjectStreamException {
+        KeyRepChild kr = new KeyRepChild(KeyRep.Type.PUBLIC, "", "",
+                new byte[] {});
+        try {
+            kr.readResolve();
+            fail("NotSerializableException has not been thrown (no format)");
+        } catch (NotSerializableException ok) {
+
+        }
+
+        kr = new KeyRepChild(KeyRep.Type.PUBLIC, "", "RAW", new byte[] {});
+        try {
+            kr.readResolve();
+            fail("NotSerializableException has not been thrown (unacceptable format)");
+        } catch (NotSerializableException ok) {
+
+        }
+
+        kr = new KeyRepChild(KeyRep.Type.PUBLIC, "bla-bla", "X.509",
+                new byte[] {});
+        try {
+            kr.readResolve();
+            fail("NotSerializableException has not been thrown (unknown KeyFactory algorithm)");
+        } catch (NotSerializableException ok) {
+
+        }
+    }
+
+    public final void testReadResolve03() throws ObjectStreamException {
+        KeyRepChild kr = new KeyRepChild(KeyRep.Type.PRIVATE, "", "",
+                new byte[] {});
+        try {
+            kr.readResolve();
+            fail("NotSerializableException has not been thrown (no format)");
+        } catch (NotSerializableException ok) {
+
+        }
+
+        kr = new KeyRepChild(KeyRep.Type.PRIVATE, "", "RAW", new byte[] {});
+        try {
+            kr.readResolve();
+            fail("NotSerializableException has not been thrown (unacceptable format)");
+        } catch (NotSerializableException ok) {
+
+        }
+
+        kr = new KeyRepChild(KeyRep.Type.PRIVATE, "bla-bla", "PKCS#8",
+                new byte[] {});
+        try {
+            kr.readResolve();
+            fail("NotSerializableException has not been thrown (unknown KeyFactory algorithm)");
+        } catch (NotSerializableException ok) {
+
+        }
+    }
+
+    public final void testReadResolve04() throws ObjectStreamException {
+        if (keyFactoryAlgorithm.isEmpty()) {
+            System.err.println(getName()
+                    + ": skipped - no KeyFactory algorithms available");
+            return;
+        } else {
+            System.out.println(getName() + ": available algorithms - "
+                    + keyFactoryAlgorithm);
+        }
+        for (Iterator<String> i = keyFactoryAlgorithm.iterator(); i.hasNext();) {
+            KeyRepChild kr = new KeyRepChild(KeyRep.Type.PUBLIC, i.next(),
+                    "X.509", new byte[] { 1, 2, 3 });
+            try {
+                kr.readResolve();
+                fail("NotSerializableException has not been thrown (no format)");
+            } catch (NotSerializableException ok) {
+
+            }
+        }
+    }
+
+    public final void testReadResolve05() throws ObjectStreamException {
+        if (keyFactoryAlgorithm.isEmpty()) {
+            System.err.println(getName()
+                    + ": skipped - no KeyFactory algorithms available");
+            return;
+        } else {
+            System.out.println(getName() + ": available algorithms - "
+                    + keyFactoryAlgorithm);
+        }
+        for (Iterator<String> i = keyFactoryAlgorithm.iterator(); i.hasNext();) {
+            KeyRepChild kr = new KeyRepChild(KeyRep.Type.PRIVATE, i.next(),
+                    "PKCS#8", new byte[] { 1, 2, 3 });
+            try {
+                kr.readResolve();
+                fail("NotSerializableException has not been thrown (no format)");
+            } catch (NotSerializableException ok) {
+
+            }
+        }
+    }
+
+    class KeyRepChild extends KeyRep {
+        public KeyRepChild(KeyRep.Type type, String algorithm, String format,
+                byte[] encoded) {
+            super(type, algorithm, format, encoded);
+        }
+
+        public Object readResolve() throws ObjectStreamException {
+            return super.readResolve();
+        }
+
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyRepTypeTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyRepTypeTest.java
new file mode 100644
index 0000000..424dd1f
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyRepTypeTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.KeyRep;
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+public class KeyRepTypeTest extends TestCase {
+
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    /**
+     * @tests java.security.KeyRep.Type#valueOf(String)
+     */
+    public void testValueOf() {
+        try {
+            KeyRep.Type.valueOf("type");
+            fail("IllegalArgumentException expected");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+        try {
+            KeyRep.Type.valueOf(null);
+            fail("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // expected
+        }
+        assertEquals(KeyRep.Type.PRIVATE, KeyRep.Type
+                .valueOf(KeyRep.Type.PRIVATE.toString()));
+        assertEquals(KeyRep.Type.PUBLIC, KeyRep.Type.valueOf(KeyRep.Type.PUBLIC
+                .toString()));
+        assertEquals(KeyRep.Type.SECRET, KeyRep.Type.valueOf(KeyRep.Type.SECRET
+                .toString()));
+    }
+
+    /**
+     * @tests java.security.KeyRep.Type#values()
+     */
+    public void testValues() {
+        KeyRep.Type[] types = new KeyRep.Type[] { KeyRep.Type.SECRET,
+                KeyRep.Type.PUBLIC, KeyRep.Type.PRIVATE };
+        try {
+            assertTrue(Arrays.equals(types, KeyRep.Type.values()));
+        } catch (Exception e) {
+            fail("Unexpected exception " + e.getMessage());
+        }
+    }
+
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyStore2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyStore2Test.java
new file mode 100644
index 0000000..ce89238
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyStore2Test.java
@@ -0,0 +1,1084 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.SignatureException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.DSAPrivateKeySpec;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import tests.support.Support_TestProvider;
+
+public class KeyStore2Test extends junit.framework.TestCase {
+    static PrivateKey privateKey;
+    static {
+        try {
+            KeyPairGenerator keyPairGenerator = KeyPairGenerator
+                    .getInstance("DSA");
+
+            SecureRandom secureRandom = new SecureRandom();
+            keyPairGenerator.initialize(1024, secureRandom);
+            KeyPair keyPair = keyPairGenerator.genKeyPair();
+            privateKey = keyPair.getPrivate();
+        } catch (Exception e) {
+            fail("initialization failed: " + e);
+        }
+    }
+
+    final char[] pssWord = { 'a', 'b', 'c' };
+
+    final byte[] testEncoding = new byte[] { (byte) 1, (byte) 2, (byte) 3,
+            (byte) 4, (byte) 5 };
+
+    private Provider support_TestProvider;
+
+    // creating a certificate
+    String certificate = "-----BEGIN CERTIFICATE-----\n"
+            + "MIICZTCCAdICBQL3AAC2MA0GCSqGSIb3DQEBAgUAMF8xCzAJBgNVBAYTAlVTMSAw\n"
+            + "HgYDVQQKExdSU0EgRGF0YSBTZWN1cml0eSwgSW5jLjEuMCwGA1UECxMlU2VjdXJl\n"
+            + "IFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05NzAyMjAwMDAwMDBa\n"
+            + "Fw05ODAyMjAyMzU5NTlaMIGWMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZv\n"
+            + "cm5pYTESMBAGA1UEBxMJUGFsbyBBbHRvMR8wHQYDVQQKExZTdW4gTWljcm9zeXN0\n"
+            + "ZW1zLCBJbmMuMSEwHwYDVQQLExhUZXN0IGFuZCBFdmFsdWF0aW9uIE9ubHkxGjAY\n"
+            + "BgNVBAMTEWFyZ29uLmVuZy5zdW4uY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB\n"
+            + "iQKBgQCofmdY+PiUWN01FOzEewf+GaG+lFf132UpzATmYJkA4AEA/juW7jSi+LJk\n"
+            + "wJKi5GO4RyZoyimAL/5yIWDV6l1KlvxyKslr0REhMBaD/3Z3EsLTTEf5gVrQS6sT\n"
+            + "WMoSZAyzB39kFfsB6oUXNtV8+UKKxSxKbxvhQn267PeCz5VX2QIDAQABMA0GCSqG\n"
+            + "SIb3DQEBAgUAA34AXl3at6luiV/7I9MN5CXYoPJYI8Bcdc1hBagJvTMcmlqL2uOZ\n"
+            + "H9T5hNMEL9Tk6aI7yZPXcw/xI2K6pOR/FrMp0UwJmdxX7ljV6ZtUZf7pY492UqwC\n"
+            + "1777XQ9UEZyrKJvF5ntleeO0ayBqLGVKCWzWZX9YsXCpv47FNLZbupE=\n"
+            + "-----END CERTIFICATE-----\n";
+
+    ByteArrayInputStream certArray = new ByteArrayInputStream(certificate
+            .getBytes());
+
+    String certificate2 = "-----BEGIN CERTIFICATE-----\n"
+            + "MIICZzCCAdCgAwIBAgIBGzANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJVUzEY\n"
+            + "MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT\n"
+            + "A1BLSTEcMBoGA1UEAxMTRG9EIFBLSSBNZWQgUm9vdCBDQTAeFw05ODA4MDMyMjAy\n"
+            + "MjlaFw0wODA4MDQyMjAyMjlaMGExCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMu\n"
+            + "IEdvdmVybm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRwwGgYDVQQD\n"
+            + "ExNEb0QgUEtJIE1lZCBSb290IENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n"
+            + "gQDbrM/J9FrJSX+zxFUbsI9Vw5QbguVBIa95rwW/0M8+sM0r5gd+DY6iubm6wnXk\n"
+            + "CSvbfQlFEDSKr4WYeeGp+d9WlDnQdtDFLdA45tCi5SHjnW+hGAmZnld0rz6wQekF\n"
+            + "5xQaa5A6wjhMlLOjbh27zyscrorMJ1O5FBOWnEHcRv6xqQIDAQABoy8wLTAdBgNV\n"
+            + "HQ4EFgQUVrmYR6m9701cHQ3r5kXyG7zsCN0wDAYDVR0TBAUwAwEB/zANBgkqhkiG\n"
+            + "9w0BAQUFAAOBgQDVX1Y0YqC7vekeZjVxtyuC8Mnxbrz6D109AX07LEIRzNYzwZ0w\n"
+            + "MTImSp9sEzWW+3FueBIU7AxGys2O7X0qmN3zgszPfSiocBuQuXIYQctJhKjF5KVc\n"
+            + "VGQRYYlt+myhl2vy6yPzEVCjiKwMEb1Spu0irCf+lFW2hsdjvmSQMtZvOw==\n"
+            + "-----END CERTIFICATE-----\n";
+
+    ByteArrayInputStream certArray2 = new ByteArrayInputStream(certificate2
+            .getBytes());
+
+    String certificate3 = "-----BEGIN CERTIFICATE-----\n"
+            + "MIIDXDCCAsWgAwIBAgIBSjANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJVUzEY\n"
+            + "MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT\n"
+            + "A1BLSTERMA8GA1UEAxMITWVkIENBLTEwHhcNOTgwODAyMTgwMjQwWhcNMDEwODAy\n"
+            + "MTgwMjQwWjB0MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50\n"
+            + "MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsTA1BLSTENMAsGA1UECxMEVVNBRjEgMB4G\n"
+            + "A1UEAxMXR3VtYnkuSm9zZXBoLjAwMDAwMDUwNDQwgZ8wDQYJKoZIhvcNAQEBBQAD\n"
+            + "gY0AMIGJAoGBALT/R7bPqs1c1YqXAg5HNpZLgW2HuAc7RCaP06cE4R44GBLw/fQc\n"
+            + "VRNLn5pgbTXsDnjiZVd8qEgYqjKFQka4/tNhaF7No2tBZB+oYL/eP0IWtP+h/W6D\n"
+            + "KR5+UvIIdgmx7k3t9jp2Q51JpHhhKEb9WN54trCO9Yu7PYU+LI85jEIBAgMBAAGj\n"
+            + "ggEaMIIBFjAWBgNVHSAEDzANMAsGCWCGSAFlAgELAzAfBgNVHSMEGDAWgBQzOhTo\n"
+            + "CWdhiGUkIOx5cELXppMe9jAdBgNVHQ4EFgQUkLBJl+ayKgzOp/wwBX9M1lSkCg4w\n"
+            + "DgYDVR0PAQH/BAQDAgbAMAwGA1UdEwEB/wQCMAAwgZ0GA1UdHwSBlTCBkjCBj6CB\n"
+            + "jKCBiYaBhmxkYXA6Ly9kcy0xLmNoYW1iLmRpc2EubWlsL2NuJTNkTWVkJTIwQ0El\n"
+            + "MmQxJTJjb3UlM2RQS0klMmNvdSUzZERvRCUyY28lM2RVLlMuJTIwR292ZXJubWVu\n"
+            + "dCUyY2MlM2RVUz9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0JTNiYmluYXJ5MA0G\n"
+            + "CSqGSIb3DQEBBQUAA4GBAFjapuDHMvIdUeYRyEYdShBR1JZC20tJ3MQnyBQveddz\n"
+            + "LGFDGpIkRAQU7T/5/ne8lMexyxViC21xOlK9LdbJCbVyywvb9uEm/1je9wieQQtr\n"
+            + "kjykuB+WB6qTCIslAO/eUmgzfzIENvnH8O+fH7QTr2PdkFkiPIqBJYHvw7F3XDqy\n"
+            + "-----END CERTIFICATE-----\n";
+
+    ByteArrayInputStream certArray3 = new ByteArrayInputStream(certificate3
+            .getBytes());
+
+    private byte[] creatCertificate() throws Exception {
+        ByteArrayOutputStream out = null;
+
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        X509Certificate cert[] = new X509Certificate[2];
+        cert[0] = (X509Certificate) cf.generateCertificate(certArray);
+        cert[1] = (X509Certificate) cf.generateCertificate(certArray2);
+        KeyStore keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+        keyTest.load(null, null);
+        // alias 1
+        keyTest.setCertificateEntry("alias1", cert[0]);
+
+        // alias 2
+        keyTest.setKeyEntry("alias2", privateKey, pssWord, cert);
+
+        // alias 3
+        keyTest.setCertificateEntry("alias3", cert[1]);
+
+        out = new ByteArrayOutputStream();
+        keyTest.store(out, pssWord);
+        out.close();
+
+        return out.toByteArray();
+    }
+
+    /**
+     * @tests java.security.KeyStore#aliases()
+     */
+    public void test_aliases() throws Exception {
+        // Test for method java.util.Enumeration
+        // java.security.KeyStore.aliases()
+        // NOT COMPATIBLE WITH PCS#12
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        X509Certificate cert[] = new X509Certificate[2];
+        cert[0] = (X509Certificate) cf.generateCertificate(certArray);
+        cert[1] = (X509Certificate) cf.generateCertificate(certArray2);
+        KeyStore keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+        keyTest.load(null, null);
+
+        // KeyStore keyTest =
+        // KeyStore.getInstance(KeyStore.getDefaultType());
+        // alias 1
+        keyTest.setCertificateEntry("alias1", cert[0]);
+
+        // alias 2
+        keyTest.setCertificateEntry("alias2", cert[0]);
+
+        // alias 3
+        keyTest.setCertificateEntry("alias3", cert[0]);
+
+        // obtaining the aliase
+        Enumeration<String> aliase = keyTest.aliases();
+        Set<String> alia = new HashSet<String>();
+        int i = 0;
+        while (aliase.hasMoreElements()) {
+            alia.add(aliase.nextElement());
+            i++;
+        }
+        assertTrue("the alias names were returned wrong", i == 3
+                && alia.contains("alias1") && alia.contains("alias2")
+                && alia.contains("alias3"));
+    }
+
+    /**
+     * @tests java.security.KeyStore#containsAlias(java.lang.String)
+     */
+    public void test_containsAliasLjava_lang_String() throws Exception {
+        // Test for method boolean
+        // java.security.KeyStore.containsAlias(java.lang.String)
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        X509Certificate cert[] = new X509Certificate[2];
+        cert[0] = (X509Certificate) cf.generateCertificate(certArray);
+        cert[1] = (X509Certificate) cf.generateCertificate(certArray2);
+        KeyStore keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+        keyTest.load(null, null);
+
+        // alias 1
+        keyTest.setCertificateEntry("alias1", cert[0]);
+
+        // alias 2
+        keyTest.setCertificateEntry("alias2", cert[0]);
+
+        assertTrue("alias1 does not exist", keyTest.containsAlias("alias1"));
+        assertTrue("alias2 does not exist", keyTest.containsAlias("alias2"));
+        assertFalse("alias3 exists", keyTest.containsAlias("alias3"));
+    }
+
+    /**
+     * @tests java.security.KeyStore#getCertificate(java.lang.String)
+     */
+    public void test_getCertificateLjava_lang_String() throws Exception {
+        // Test for method java.security.cert.Certificate
+        // java.security.KeyStore.getCertificate(java.lang.String)
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        X509Certificate cert[] = new X509Certificate[2];
+        cert[0] = (X509Certificate) cf.generateCertificate(certArray);
+        cert[1] = (X509Certificate) cf.generateCertificate(certArray2);
+        KeyStore keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+        keyTest.load(null, null);
+
+        // alias 1
+        PublicKey pub = cert[0].getPublicKey();
+        keyTest.setCertificateEntry("alias1", cert[0]);
+
+        java.security.cert.Certificate certRes = keyTest
+                .getCertificate("alias1");
+        assertTrue("the public key of the certificate from getCertificate() "
+                + "did not equal the original certificate", certRes
+                .getPublicKey() == pub);
+
+        // alias 2
+        keyTest.setCertificateEntry("alias2", cert[0]);
+
+        // testing for a certificate chain
+        java.security.cert.Certificate cert2 = keyTest.getCertificate("alias2");
+        assertTrue("the certificate for alias2 is supposed to exist",
+                cert2 != null && cert2.equals(cert[0]));
+
+    }
+
+    /**
+     * @tests java.security.KeyStore#getCertificateAlias(java.security.cert.Certificate)
+     */
+    public void test_getCertificateAliasLjava_security_cert_Certificate()
+            throws Exception {
+        // Test for method java.lang.String
+        // java.security.KeyStore.getCertificateAlias(java.security.cert.Certificate)
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        X509Certificate cert[] = new X509Certificate[2];
+        cert[0] = (X509Certificate) cf.generateCertificate(certArray);
+        cert[1] = (X509Certificate) cf.generateCertificate(certArray2);
+        KeyStore keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+        keyTest.load(null, null);
+
+        // certificate entry
+        keyTest.setCertificateEntry("alias1", cert[1]);
+        String alias = keyTest.getCertificateAlias(cert[1]);
+        assertTrue("certificate entry - the alias returned for this "
+                + "certificate was wrong", alias.equals("alias1"));
+
+        // key entry
+
+        keyTest.setKeyEntry("alias2", privateKey, pssWord, cert);
+        alias = keyTest.getCertificateAlias(cert[0]);
+        assertTrue("key entry - the alias returned for this "
+                + "certificate was wrong", alias.equals("alias2"));
+
+        // testing case with a nonexistent certificate
+        X509Certificate cert2 = (X509Certificate) cf
+                .generateCertificate(certArray3);
+        String aliasNull = keyTest.getCertificateAlias(cert2);
+        assertNull("the alias returned for the nonexist certificate "
+                + "was NOT null", aliasNull);
+    }
+
+    /**
+     * @tests java.security.KeyStore#getCertificateChain(java.lang.String)
+     */
+    public void test_getCertificateChainLjava_lang_String() throws Exception {
+        // Test for method java.security.cert.Certificate []
+        // java.security.KeyStore.getCertificateChain(java.lang.String)
+        // creatCertificate();
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        X509Certificate cert[] = new X509Certificate[2];
+        cert[0] = (X509Certificate) cf.generateCertificate(certArray);
+        cert[1] = (X509Certificate) cf.generateCertificate(certArray2);
+        KeyStore keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+        keyTest.load(null, null);
+
+        // alias 1
+        keyTest.setCertificateEntry("alias1", cert[0]);
+
+        // alias 2
+        keyTest.setKeyEntry("alias2", privateKey, pssWord, cert);
+
+        java.security.cert.Certificate[] certRes = keyTest
+                .getCertificateChain("alias2");
+        assertTrue("there are more than two certificate returned "
+                + "from getCertificateChain", certRes.length == 2);
+        assertTrue("the certificates returned from getCertificateChain "
+                + "is not correct", cert[0].getPublicKey() == certRes[0]
+                .getPublicKey()
+                && cert[1].getPublicKey() == certRes[1].getPublicKey());
+        java.security.cert.Certificate[] certResNull = keyTest
+                .getCertificateChain("alias1");
+        assertNull("the certificate chain returned from "
+                + "getCertificateChain is NOT null", certResNull);
+    }
+
+    /**
+     * @tests java.security.KeyStore#getInstance(java.lang.String)
+     */
+    public void test_getInstanceLjava_lang_String() throws Exception {
+        // Test for method java.security.KeyStore
+        // java.security.KeyStore.getInstance(java.lang.String)
+        KeyStore keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+        assertTrue("the method getInstance did not obtain "
+                + "the correct type", keyTest.getType().equals(
+                KeyStore.getDefaultType()));
+    }
+
+    /**
+     * @tests java.security.KeyStore#getInstance(java.lang.String,
+     *        java.lang.String)
+     */
+    public void test_getInstanceLjava_lang_StringLjava_lang_String() {
+        // Test for method java.security.KeyStore
+        // java.security.KeyStore.getInstance(java.lang.String,
+        // java.lang.String)
+        try {
+            KeyStore keyTest = KeyStore.getInstance("PKCS#12/Netscape",
+                    "TestProvider");
+            assertTrue("the method getInstance did not obtain the "
+                    + "correct provider and type", keyTest.getProvider()
+                    .getName().equals("TestProvider")
+                    && keyTest.getType().equals("PKCS#12/Netscape"));
+        } catch (KeyStoreException e) {
+            fail("Unexpected KeyStoreException " + e.getMessage());
+        } catch (NoSuchProviderException e) {
+            fail("Unexpected NoSuchProviderException " + e.getMessage());
+        }
+
+    }
+
+    /**
+     * @tests java.security.KeyStore#getInstance(java.lang.String,
+     *        java.security.Provider)
+     */
+    public void test_getInstanceLjava_lang_StringLjava_security_Provider() {
+        // Test for method java.security.KeyStore
+        // java.security.KeyStore.getInstance(java.lang.String,
+        // java.security.Provider)
+        try {
+            KeyStore keyTest = KeyStore.getInstance("PKCS#12/Netscape",
+                    support_TestProvider);
+            assertTrue("the method getInstance did not obtain the "
+                    + "correct provider and type", keyTest.getProvider()
+                    .getName().equals("TestProvider")
+                    && keyTest.getType().equals("PKCS#12/Netscape"));
+        } catch (KeyStoreException e) {
+            fail("Unexpected KeyStoreException " + e.getMessage());
+        } catch (Exception e) {
+            fail("Unexpected Exception " + e.getMessage());
+        }
+
+        try {
+            KeyStore.getInstance(null, (Provider) null);
+            fail("IllegalArgumentException expected");
+        } catch (IllegalArgumentException e) {
+            // expected
+        } catch (Exception e) {
+            fail("Unexpected Exception " + e.getMessage());
+        }
+    }
+
+    /**
+     * @tests java.security.KeyStore#getKey(java.lang.String, char[])
+     */
+    public void test_getKeyLjava_lang_String$C() throws Exception {
+
+        // Test for method java.security.Key
+        // java.security.KeyStore.getKey(java.lang.String, char [])
+        // creatCertificate();
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        X509Certificate cert[] = new X509Certificate[2];
+        cert[0] = (X509Certificate) cf.generateCertificate(certArray);
+        cert[1] = (X509Certificate) cf.generateCertificate(certArray2);
+        KeyStore keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+        keyTest.load(null, null);
+
+        keyTest.setKeyEntry("alias2", privateKey, pssWord, cert);
+        PrivateKey returnedKey = (PrivateKey) keyTest.getKey("alias2", pssWord);
+        byte[] retB = returnedKey.getEncoded();
+        byte[] priB = privateKey.getEncoded();
+        boolean equality = Arrays.equals(retB, priB);
+        equality &= returnedKey.getAlgorithm()
+                .equals(privateKey.getAlgorithm());
+        equality &= returnedKey.getFormat().equals(privateKey.getFormat());
+        assertTrue("the private key returned from getKey for a "
+                + "key entry did not equal the original key", equality);
+
+        try {
+            keyTest.getKey("alias2", "wrong".toCharArray());
+            fail("Should have thrown UnrecoverableKeyException");
+        } catch (UnrecoverableKeyException e) {
+            // expected
+        }
+
+        keyTest.setCertificateEntry("alias1", cert[1]);
+        assertNull("the private key returned from getKey for "
+                + "a certificate entry is not null", keyTest.getKey("alias1",
+                pssWord));
+    }
+
+    /**
+     * @tests java.security.KeyStore#getProvider()
+     */
+    public void test_getProvider() {
+        // Test for method java.security.Provider
+        // java.security.KeyStore.getProvider()
+        try {
+            KeyStore keyTest = KeyStore.getInstance("PKCS#12/Netscape",
+                    "TestProvider");
+            Provider provKeyStore = keyTest.getProvider();
+            assertEquals("the provider should be TestProvider", "TestProvider",
+                    provKeyStore.getName());
+        } catch (KeyStoreException e) {
+            fail("Unexpected KeyStoreException " + e.getMessage());
+        } catch (NoSuchProviderException e) {
+            fail("Unexpected NoSuchProviderException " + e.getMessage());
+        }
+    }
+
+    /**
+     * @tests java.security.KeyStore#getType()
+     */
+    public void test_getType() {
+        // Test for method java.lang.String java.security.KeyStore.getType()
+        try {
+
+            KeyStore keyTest = KeyStore.getInstance("PKCS#12/Netscape",
+                    "TestProvider");
+            assertEquals(
+                    "type should be PKCS#12/Netscape for provider TestProvider",
+                    "PKCS#12/Netscape", keyTest.getType());
+        } catch (KeyStoreException e) {
+            fail("Unexpected KeyStoreException " + e.getMessage());
+        } catch (NoSuchProviderException e) {
+            fail("Unexpected NoSuchProviderException " + e.getMessage());
+        }
+    }
+
+    /**
+     * @tests java.security.KeyStore#isCertificateEntry(java.lang.String)
+     */
+    public void test_isCertificateEntryLjava_lang_String() throws Exception {
+        // Test for method boolean
+        // java.security.KeyStore.isCertificateEntry(java.lang.String)
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        X509Certificate cert[] = new X509Certificate[2];
+        cert[0] = (X509Certificate) cf.generateCertificate(certArray);
+        cert[1] = (X509Certificate) cf.generateCertificate(certArray2);
+        KeyStore keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+        keyTest.load(null, null);
+        // alias 1
+        keyTest.setCertificateEntry("alias1", cert[0]);
+
+        // alias 2
+        keyTest.setKeyEntry("alias2", privateKey, pssWord, cert);
+
+        assertTrue("isCertificateEntry method returns false for a certificate",
+                keyTest.isCertificateEntry("alias1"));
+        assertFalse(
+                "isCertificateEntry method returns true for noncertificate",
+                keyTest.isCertificateEntry("alias2"));
+    }
+
+    /**
+     * @tests java.security.KeyStore#isKeyEntry(java.lang.String)
+     */
+    public void test_isKeyEntryLjava_lang_String() throws Exception {
+        // Test for method boolean
+        // java.security.KeyStore.isKeyEntry(java.lang.String)
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        X509Certificate cert[] = new X509Certificate[2];
+        cert[0] = (X509Certificate) cf.generateCertificate(certArray);
+        cert[1] = (X509Certificate) cf.generateCertificate(certArray2);
+        KeyStore keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+        keyTest.load(null, null);
+        // alias 1
+        keyTest.setCertificateEntry("alias1", cert[0]);
+
+        // alias 2
+        keyTest.setKeyEntry("alias2", privateKey, pssWord, cert);
+
+        assertTrue("isKeyEntry method returns false for a certificate", keyTest
+                .isKeyEntry("alias2"));
+        assertFalse("isKeyEntry method returns true for noncertificate",
+                keyTest.isKeyEntry("alias1"));
+    }
+
+    /**
+     * @tests java.security.KeyStore#load(java.io.InputStream, char[])
+     */
+    public void test_loadLjava_io_InputStream$C() throws Exception {
+        // Test for method void java.security.KeyStore.load(java.io.InputStream,
+        // char [])
+        byte[] keyStore = creatCertificate();
+        KeyStore keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+        InputStream in = new ByteArrayInputStream(keyStore);
+        keyTest.load(in, pssWord);
+        in.close();
+        assertTrue("alias1 is not a certificate", keyTest
+                .isCertificateEntry("alias1"));
+        assertTrue("alias2 is not a keyEntry", keyTest.isKeyEntry("alias2"));
+        assertTrue("alias3 is not a certificate", keyTest
+                .isCertificateEntry("alias3"));
+
+        // test with null password
+        keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+        in = new ByteArrayInputStream(keyStore);
+        keyTest.load(in, null);
+        in.close();
+        assertTrue("alias1 is not a certificate", keyTest
+                .isCertificateEntry("alias1"));
+        assertTrue("alias2 is not a keyEntry", keyTest.isKeyEntry("alias2"));
+        assertTrue("alias3 is not a certificate", keyTest
+                .isCertificateEntry("alias3"));
+
+        keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+        
+        InputStream v1in = new FileInputStream(ClassLoader
+                .getSystemClassLoader().getResource("keystore.jks").getFile());
+
+        char[] pass = "password".toCharArray();
+        keyTest.load(v1in, pass);
+        v1in.close();
+        assertNull(keyTest.getKey("mykey", pass));
+        assertNotNull(keyTest.getKey("testkeystore", pass));
+    }
+
+    /**
+     * @tests java.security.KeyStore#load(KeyStore.LoadStoreParameter param)
+     */
+    public void test_loadLjava_security_KeyStoreLoadStoreParameter() {
+        try {
+            KeyStore keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+            keyTest.load(null);
+            
+        } catch (Exception e ) {
+            fail("Unexpected exception " + e.getMessage());
+        }
+        
+        
+    }
+    /**
+     * @tests java.security.KeyStore#setCertificateEntry(java.lang.String,
+     *        java.security.cert.Certificate)
+     */
+    public void test_setCertificateEntryLjava_lang_StringLjava_security_cert_Certificate()
+            throws Exception {
+        // Test for method void
+        // java.security.KeyStore.setCertificateEntry(java.lang.String,
+        // java.security.cert.Certificate)
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        X509Certificate cert = (X509Certificate) cf
+                .generateCertificate(certArray);
+        KeyStore keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+        keyTest.load(null, null);
+
+        PublicKey pub = cert.getPublicKey();
+        keyTest.setCertificateEntry("alias1", cert);
+        assertTrue(
+                "the entry specified by the alias alias1 is not a certificate",
+                keyTest.isCertificateEntry("alias1"));
+        java.security.cert.Certificate resultCert = keyTest
+                .getCertificate("alias1");
+        assertTrue(
+                "the public key of the certificate from getCertificate() did not equal the original certificate",
+                resultCert.getPublicKey() == pub);
+    }
+
+    /**
+     * @tests java.security.KeyStore#setKeyEntry(java.lang.String,
+     *        java.security.Key, char[], java.security.cert.Certificate[])
+     */
+    public void test_setKeyEntryLjava_lang_StringLjava_security_Key$C$Ljava_security_cert_Certificate()
+            throws Exception {
+
+        // Test for method void
+        // java.security.KeyStore.setKeyEntry(java.lang.String,
+        // java.security.Key, char [], java.security.cert.Certificate [])
+
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        X509Certificate cert[] = new X509Certificate[2];
+        cert[0] = (X509Certificate) cf.generateCertificate(certArray);
+        cert[1] = (X509Certificate) cf.generateCertificate(certArray2);
+        KeyStore keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+        keyTest.load(null, null);
+
+        keyTest.setKeyEntry("alias3", privateKey, pssWord, cert);
+        assertTrue("the entry specified by the alias alias3 is not a keyEntry",
+                keyTest.isKeyEntry("alias3"));
+    }
+
+    /**
+     * @tests java.security.KeyStore#size()
+     */
+    public void test_size() throws Exception {
+        // Test for method int java.security.KeyStore.size()
+
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        X509Certificate cert[] = new X509Certificate[2];
+        cert[0] = (X509Certificate) cf.generateCertificate(certArray);
+        cert[1] = (X509Certificate) cf.generateCertificate(certArray2);
+        KeyStore keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+        keyTest.load(null, null);
+        // alias 1
+        keyTest.setCertificateEntry("alias1", cert[0]);
+
+        // alias 2
+        keyTest.setKeyEntry("alias2", privateKey, pssWord, cert);
+
+        // alias 3
+        keyTest.setCertificateEntry("alias3", cert[1]);
+
+        assertEquals("the size of the keyStore is not 3", 3, keyTest.size());
+    }
+
+    /**
+     * @tests java.security.KeyStore#deleteEntry(String)
+     */
+    public void test_deleteEntry() {
+        try {
+            KeyStore keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+            keyTest.load(null, null);
+            keyTest.deleteEntry(null);
+            fail("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // expected
+        } catch (Exception e) {
+            fail("Unexpected Exception " + e.getMessage());
+        }
+
+        try {
+            KeyStore keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+            keyTest.load(null, null);
+            keyTest.deleteEntry("");
+        } catch (Exception e) {
+            fail("Unexpected Exception " + e.getMessage());
+        }
+
+        try {
+            KeyStore keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+            keyTest.load(null, null);
+            keyTest.deleteEntry("entry");
+        } catch (Exception e) {
+            fail("Unexpected Exception " + e.getMessage());
+        }
+
+        try {
+            KeyStore keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+            keyTest.load(null, "password".toCharArray());
+
+            KeyStore.PasswordProtection pp = new KeyStore.PasswordProtection(
+                    pssWord);
+            Certificate[] chain = { new MyCertificate("DSA", testEncoding),
+                    new MyCertificate("DSA", testEncoding) };
+            KeyStore.PrivateKeyEntry pkEntry = new KeyStore.PrivateKeyEntry(
+                    privateKey, chain);
+
+            keyTest.setEntry("symKey", pkEntry, pp);
+
+        } catch (KeyStoreException e) {
+            fail("Unexpected KeyStoreException " + e.getMessage());
+        } catch (IOException e) {
+            fail("Unexpected IOException " + e.getMessage());
+        } catch (NoSuchAlgorithmException e) {
+            fail("Unexpected NoSuchAlgorithmException " + e.getMessage());
+        } catch (CertificateException e) {
+            fail("Unexpected CertificateException " + e.getMessage());
+        } catch (Exception e) {
+            fail("Unexpected Exception " + e.getMessage());
+        }
+
+    }
+
+    /**
+     * @tests java.security.KeyStore#getCreationDate(String)
+     */
+    public void test_getCreationDate() throws Exception {
+        String type = "DSA";
+
+        KeyStore keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+        keyTest.load(null, pssWord);
+
+        assertNull(keyTest.getCreationDate(""));
+        try {
+            keyTest.getCreationDate(null);
+            fail("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // expected
+        }
+
+        Certificate[] chain = { new MyCertificate(type, testEncoding),
+                new MyCertificate(type, testEncoding) };
+        PrivateKey privateKey1 = KeyFactory.getInstance(type).generatePrivate(
+                new DSAPrivateKeySpec(new BigInteger("0"), new BigInteger("0"),
+                        new BigInteger("0"), new BigInteger("0")));
+
+        KeyStore.PasswordProtection pp = new KeyStore.PasswordProtection(
+                pssWord);
+        KeyStore.PrivateKeyEntry pke = new KeyStore.PrivateKeyEntry(privateKey,
+                chain);
+        KeyStore.PrivateKeyEntry pke1 = new KeyStore.PrivateKeyEntry(
+                privateKey1, chain);
+
+        keyTest.setEntry("alias1", pke, pp);
+        keyTest.setEntry("alias2", pke1, pp);
+        Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
+
+        int dayExpected = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
+        int monthExpected = Calendar.getInstance().get(Calendar.MONTH);
+        int yearExpected = Calendar.getInstance().get(Calendar.YEAR);
+        int hourExpected = Calendar.getInstance().get(Calendar.HOUR);
+        int minuteExpected = Calendar.getInstance().get(Calendar.MINUTE);
+
+        Calendar.getInstance().setTimeInMillis(
+                keyTest.getCreationDate("alias1").getTime());
+        int dayActual1 = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
+        int monthActual1 = Calendar.getInstance().get(Calendar.MONTH);
+        int yearActual1 = Calendar.getInstance().get(Calendar.YEAR);
+        int hourActual1 = Calendar.getInstance().get(Calendar.HOUR);
+        int minuteActual1 = Calendar.getInstance().get(Calendar.MINUTE);
+
+        assertEquals(dayExpected, dayActual1);
+        assertEquals(monthExpected, monthActual1);
+        assertEquals(yearExpected, yearActual1);
+        assertEquals(hourExpected, hourActual1);
+        assertEquals(minuteExpected, minuteActual1);
+
+        Calendar.getInstance().setTimeInMillis(
+                keyTest.getCreationDate("alias2").getTime());
+        int dayActual2 = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
+        int monthActual2 = Calendar.getInstance().get(Calendar.MONTH);
+        int yearActual2 = Calendar.getInstance().get(Calendar.YEAR);
+        int hourActual2 = Calendar.getInstance().get(Calendar.HOUR);
+        int minuteActual2 = Calendar.getInstance().get(Calendar.MINUTE);
+
+        assertEquals(dayExpected, dayActual2);
+        assertEquals(monthExpected, monthActual2);
+        assertEquals(yearExpected, yearActual2);
+        assertEquals(hourExpected, hourActual2);
+        assertEquals(minuteExpected, minuteActual2);
+    }
+
+    /**
+     * @tests java.security.KeyStore#getDefaultType()
+     */
+    public void test_getDefaultType() {
+        assertEquals("jks", KeyStore.getDefaultType());
+    }
+
+    /**
+     * @tests java.security.KeyStore#getEntry(String,
+     *        KeyStore.ProtectionParameter)
+     */
+    public void test_getEntry() {
+        String type = "DSA";
+        KeyStore keyTest = null;
+        KeyStore.PasswordProtection pp = null;
+
+        try {
+            keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+            keyTest.load(null, pssWord);
+
+            assertNull(keyTest.getEntry("alias", pp));
+
+            Certificate[] chain = { new MyCertificate(type, testEncoding),
+                    new MyCertificate(type, testEncoding) };
+
+            PrivateKey privateKey1 = KeyFactory.getInstance(type)
+                    .generatePrivate(
+                            new DSAPrivateKeySpec(new BigInteger("0"),
+                                    new BigInteger("0"), new BigInteger("0"),
+                                    new BigInteger("0")));
+
+            pp = new KeyStore.PasswordProtection(pssWord);
+
+            assertNull(keyTest.getEntry("alias", pp));
+
+            KeyStore.PrivateKeyEntry pke1 = new KeyStore.PrivateKeyEntry(
+                    privateKey, chain);
+            KeyStore.PrivateKeyEntry pke2 = new KeyStore.PrivateKeyEntry(
+                    privateKey1, chain);
+
+            keyTest.setEntry("alias1", pke1, pp);
+            keyTest.setEntry("alias2", pke2, pp);
+
+            assertNull(keyTest.getEntry("alias", pp));
+            KeyStore.PrivateKeyEntry pkeActual1 = (KeyStore.PrivateKeyEntry) keyTest
+                    .getEntry("alias1", pp);
+            KeyStore.PrivateKeyEntry pkeActual2 = (KeyStore.PrivateKeyEntry) keyTest
+                    .getEntry("alias2", pp);
+
+            assertTrue(Arrays.equals(chain, pkeActual1.getCertificateChain()));
+            assertEquals(privateKey, pkeActual1.getPrivateKey());
+            assertEquals(new MyCertificate(type, testEncoding), pkeActual1
+                    .getCertificate());
+            assertTrue(keyTest.entryInstanceOf("alias1",
+                    KeyStore.PrivateKeyEntry.class));
+
+            assertTrue(Arrays.equals(chain, pkeActual2.getCertificateChain()));
+            assertEquals(privateKey1, pkeActual2.getPrivateKey());
+            assertEquals(new MyCertificate(type, testEncoding), pkeActual2
+                    .getCertificate());
+            assertTrue(keyTest.entryInstanceOf("alias2",
+                    KeyStore.PrivateKeyEntry.class));
+
+        } catch (Exception e) {
+            fail("Unexpected exception " + e.getMessage());
+        }
+
+        try {
+            keyTest.getEntry(null, null);
+            fail("Exception expected");
+        } catch (Exception e) {
+            // expected
+        }
+
+    }
+
+    /**
+     * @tests java.security.KeyStore#setEntry(String, KeyStore.Entry,
+     *        KeyStore.ProtectionParameter)
+     */
+    public void test_setEntry() {
+        String type = "DSA";
+        KeyStore keyTest = null;
+        KeyStore.PasswordProtection pp = null;
+
+        try {
+            keyTest = KeyStore.getInstance(KeyStore.getDefaultType());
+            keyTest.load(null, pssWord);
+
+            Certificate[] chain = { new MyCertificate(type, testEncoding),
+                    new MyCertificate(type, testEncoding) };
+            PrivateKey privateKey1 = KeyFactory.getInstance(type)
+                    .generatePrivate(
+                            new DSAPrivateKeySpec(new BigInteger("0"),
+                                    new BigInteger("0"), new BigInteger("0"),
+                                    new BigInteger("0")));
+
+            pp = new KeyStore.PasswordProtection(pssWord);
+            KeyStore.PrivateKeyEntry pke = new KeyStore.PrivateKeyEntry(
+                    privateKey, chain);
+            KeyStore.PrivateKeyEntry pke1 = new KeyStore.PrivateKeyEntry(
+                    privateKey1, chain);
+
+            try {
+                keyTest.setEntry("alias", pke, null);
+                fail("Exception expected");
+            } catch (Exception e) {
+                // expected
+            }
+
+            keyTest.setEntry("alias", pke, pp);
+
+            KeyStore.PrivateKeyEntry pkeActual = (KeyStore.PrivateKeyEntry) keyTest
+                    .getEntry("alias", pp);
+
+            assertTrue(Arrays.equals(chain, pkeActual.getCertificateChain()));
+            assertEquals(privateKey, pkeActual.getPrivateKey());
+            assertEquals(new MyCertificate(type, testEncoding), pkeActual
+                    .getCertificate());
+            assertTrue(keyTest.entryInstanceOf("alias",
+                    KeyStore.PrivateKeyEntry.class));
+
+            keyTest.setEntry("alias", pke1, pp);
+            pkeActual = (KeyStore.PrivateKeyEntry) keyTest
+                    .getEntry("alias", pp);
+
+            assertTrue(Arrays.equals(chain, pkeActual.getCertificateChain()));
+            assertEquals(privateKey1, pkeActual.getPrivateKey());
+            assertEquals(new MyCertificate(type, testEncoding), pkeActual
+                    .getCertificate());
+            assertTrue(keyTest.entryInstanceOf("alias",
+                    KeyStore.PrivateKeyEntry.class));
+
+            keyTest.setEntry("alias2", pke1, pp);
+            pkeActual = (KeyStore.PrivateKeyEntry) keyTest.getEntry("alias2",
+                    pp);
+
+            assertTrue(Arrays.equals(chain, pkeActual.getCertificateChain()));
+            assertEquals(privateKey1, pkeActual.getPrivateKey());
+            assertEquals(new MyCertificate(type, testEncoding), pkeActual
+                    .getCertificate());
+            assertTrue(keyTest.entryInstanceOf("alias2",
+                    KeyStore.PrivateKeyEntry.class));
+
+        } catch (Exception e) {
+            fail("Unexpected exception " + e.getMessage());
+        }
+
+        SecretKey sk = new SecretKeySpec(testEncoding, type);
+        KeyStore.SecretKeyEntry ske = new KeyStore.SecretKeyEntry(sk);
+        try {
+            keyTest.setEntry("alias1", ske, pp);
+            fail("KeyStoreException expected");
+        } catch (KeyStoreException e) {
+            // expected
+        }
+
+        KeyStore.TrustedCertificateEntry tse = new KeyStore.TrustedCertificateEntry(
+                new MyCertificate(type, testEncoding));
+        try {
+            keyTest.setEntry("alias2", tse, pp);
+            fail("KeyStoreException expected");
+        } catch (KeyStoreException e) {
+            // expected
+        }
+
+        try {
+            keyTest.setEntry(null, null, null);
+            fail("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // expected
+        } catch (Exception e) {
+            fail("Unexpected exception");
+        }
+
+    }
+
+    /*
+     * @tests java.security.KeyStore.entryInstanceOf(String, Class<? extends
+     * Entry>)
+     */
+    public void test_entryInstanceOf() throws Exception {
+
+        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+        keyStore.load(null, "pwd".toCharArray());
+
+        // put the key into keystore
+        String alias = "alias";
+        Certificate[] chain = { new MyCertificate("DSA", testEncoding),
+                new MyCertificate("DSA", testEncoding) };
+
+        keyStore.setKeyEntry(alias, privateKey, "pwd".toCharArray(), chain);
+
+        assertTrue(keyStore.entryInstanceOf(alias,
+                KeyStore.PrivateKeyEntry.class));
+
+        assertFalse(keyStore.entryInstanceOf(alias,
+                KeyStore.SecretKeyEntry.class));
+
+        assertFalse(keyStore.entryInstanceOf(alias,
+                KeyStore.TrustedCertificateEntry.class));
+    }
+
+    /**
+     * @tests java.security.KeyStore#store(KeyStore.LoadStoreParameter)
+     */
+    public void test_store_java_securityKeyStore_LoadStoreParameter()
+            throws Exception {
+        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+        keyStore.load(null, "pwd".toCharArray());
+        try {
+            keyStore.store(null);
+            fail("UnsupportedOperationException expected");
+        } catch (UnsupportedOperationException e) {
+            // expected
+        }
+    }
+
+    /**
+     * @tests java.security.KeyStore#store(OutputStream, char[])
+     */
+    public void test_store_java_io_OutputStream_char() throws Exception {
+        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+        keyStore.load(null, "pwd".toCharArray());
+        try {
+            keyStore.store(null, "pwd".toCharArray());
+            fail("UnsupportedOperationException expected");
+        } catch (NullPointerException e) {
+            // expected
+        } catch (Exception e) {
+            fail("Unexpected exception " + e.getMessage());
+        }
+        
+        try {
+            keyStore.store(null, null);
+            fail("IllegalArgumentException expected");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    /**
+     * Sets up the fixture, for example, open a network connection. This method
+     * is called before a test is executed.
+     */
+    protected void setUp() throws Exception {
+        super.setUp();
+        support_TestProvider = new Support_TestProvider();
+        Security.addProvider(support_TestProvider);
+    }
+
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        Security.removeProvider(support_TestProvider.getName());
+    }
+
+    class MyCertificate extends Certificate {
+
+        // MyCertificate encoding
+        private final byte[] encoding;
+
+        public MyCertificate(String type, byte[] encoding) {
+            super(type);
+            // don't copy to allow null parameter in test
+            this.encoding = encoding;
+        }
+
+        public byte[] getEncoded() throws CertificateEncodingException {
+            // do copy to force NPE in test
+            return encoding.clone();
+        }
+
+        public void verify(PublicKey key) throws CertificateException,
+                NoSuchAlgorithmException, InvalidKeyException,
+                NoSuchProviderException, SignatureException {
+        }
+
+        public void verify(PublicKey key, String sigProvider)
+                throws CertificateException, NoSuchAlgorithmException,
+                InvalidKeyException, NoSuchProviderException,
+                SignatureException {
+        }
+
+        public String toString() {
+            return "[My test Certificate, type: " + getType() + "]";
+        }
+
+        public PublicKey getPublicKey() {
+            return new PublicKey() {
+                public String getAlgorithm() {
+                    return "DSA";
+                }
+
+                public byte[] getEncoded() {
+                    return new byte[] { (byte) 1, (byte) 2, (byte) 3 };
+                }
+
+                public String getFormat() {
+                    return "TEST_FORMAT";
+                }
+            };
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyStore3Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyStore3Test.java
new file mode 100644
index 0000000..b6c87b9
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyStore3Test.java
@@ -0,0 +1,243 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.KeyStoreSpi;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.util.Date;
+import java.util.Enumeration;
+
+import junit.framework.TestCase;
+
+public class KeyStore3Test extends TestCase {
+    
+    private KeyStore mockKeyStore;
+    
+    private KeyPair keyPair;
+    
+    private Certificate certificate;
+    
+    public KeyStore3Test() throws Exception {
+        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");
+        keyPair = keyPairGenerator.generateKeyPair();
+
+        String certificateData = "-----BEGIN CERTIFICATE-----\n"
+                + "MIICZTCCAdICBQL3AAC2MA0GCSqGSIb3DQEBAgUAMF8xCzAJBgNVBAYTAlVTMSAw\n"
+                + "HgYDVQQKExdSU0EgRGF0YSBTZWN1cml0eSwgSW5jLjEuMCwGA1UECxMlU2VjdXJl\n"
+                + "IFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05NzAyMjAwMDAwMDBa\n"
+                + "Fw05ODAyMjAyMzU5NTlaMIGWMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZv\n"
+                + "cm5pYTESMBAGA1UEBxMJUGFsbyBBbHRvMR8wHQYDVQQKExZTdW4gTWljcm9zeXN0\n"
+                + "ZW1zLCBJbmMuMSEwHwYDVQQLExhUZXN0IGFuZCBFdmFsdWF0aW9uIE9ubHkxGjAY\n"
+                + "BgNVBAMTEWFyZ29uLmVuZy5zdW4uY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB\n"
+                + "iQKBgQCofmdY+PiUWN01FOzEewf+GaG+lFf132UpzATmYJkA4AEA/juW7jSi+LJk\n"
+                + "wJKi5GO4RyZoyimAL/5yIWDV6l1KlvxyKslr0REhMBaD/3Z3EsLTTEf5gVrQS6sT\n"
+                + "WMoSZAyzB39kFfsB6oUXNtV8+UKKxSxKbxvhQn267PeCz5VX2QIDAQABMA0GCSqG\n"
+                + "SIb3DQEBAgUAA34AXl3at6luiV/7I9MN5CXYoPJYI8Bcdc1hBagJvTMcmlqL2uOZ\n"
+                + "H9T5hNMEL9Tk6aI7yZPXcw/xI2K6pOR/FrMp0UwJmdxX7ljV6ZtUZf7pY492UqwC\n"
+                + "1777XQ9UEZyrKJvF5ntleeO0ayBqLGVKCWzWZX9YsXCpv47FNLZbupE=\n"
+                + "-----END CERTIFICATE-----\n";
+
+        ByteArrayInputStream certArray = new ByteArrayInputStream(
+                certificateData.getBytes());
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        certificate = cf.generateCertificate(certArray);
+    }
+    
+    public void test_load() throws Exception {
+        // No exception should be thrown out.
+        mockKeyStore.load(null);
+    }
+
+    public void test_store() throws Exception {
+        try {
+            mockKeyStore.store(null);
+            fail("should throw KeyStoreException: not initialized");
+        } catch (KeyStoreException e) {
+            // expected
+        }
+        
+        // No exception should be thrown out.
+        mockKeyStore.load(null, null);
+        mockKeyStore.store(null);
+    }
+
+    public void test_setKeyEntry_null() throws Exception {
+        mockKeyStore.load(null, null); 
+        // No exception should be thrown out.
+        mockKeyStore.setKeyEntry(null, null, null, null);        
+    }
+    
+    public void test_setKeyEntry_key_is_null() throws Exception {
+        mockKeyStore.load(null, null);
+        // No exception should be thrown out.
+        mockKeyStore.setKeyEntry("Alias", null, null, new Certificate[]{certificate});        
+    }
+    
+    public void test_setKeyEntry_key_is_private() throws Exception {
+        mockKeyStore.load(null, null);
+        Key key = keyPair.getPrivate();
+        try {
+            mockKeyStore.setKeyEntry("Alias", key, null, null);
+            fail("should throw IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+        
+        try {
+            mockKeyStore.setKeyEntry("Alias", key, null,
+                    new Certificate[0]);
+            fail("should throw IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+        
+        mockKeyStore.setKeyEntry("Alias", key, null, new Certificate[]{certificate});        
+    }
+    
+    public void test_setKeyEntry_key_is_public() throws Exception
+    {
+        mockKeyStore.load(null, null);
+        Key key = keyPair.getPublic();
+        mockKeyStore.setKeyEntry("Alias1", key, null, null);
+        mockKeyStore.setKeyEntry("Alias2", key, null,
+                new Certificate[0]);
+        mockKeyStore.setKeyEntry("Alias3", key, null, new Certificate[]{certificate});
+    }
+    
+    public void test_setCertificateEntry_null() throws Exception {
+        mockKeyStore.load(null, null);
+
+        mockKeyStore.setCertificateEntry(null, null);
+
+        mockKeyStore.setCertificateEntry(null, certificate);
+
+        mockKeyStore.setCertificateEntry("Alias", null);
+    }
+    
+    public void test_store_null() throws Exception {
+        mockKeyStore.load(null, null);
+        mockKeyStore.store(null, null);
+    }
+    
+    protected void setUp() throws Exception {
+        super.setUp();
+        mockKeyStore = new MyKeyStore(new MyKeyStoreSpi(), null, "MyKeyStore");
+    }
+    
+    private static class MyKeyStore extends KeyStore {
+
+        public MyKeyStore(KeyStoreSpi keyStoreSpi, Provider provider,
+                String type) {
+            super(keyStoreSpi, provider, type);
+        }
+    }
+
+    private static class MyKeyStoreSpi extends KeyStoreSpi {
+
+        public Enumeration<String> engineAliases() {
+            return null;
+        }
+
+        public boolean engineContainsAlias(String arg0) {
+            return false;
+        }
+
+        public void engineDeleteEntry(String arg0) throws KeyStoreException {
+        }
+
+        public Certificate engineGetCertificate(String arg0) {
+            return null;
+        }
+
+        public String engineGetCertificateAlias(Certificate arg0) {
+            return null;
+        }
+
+        public Certificate[] engineGetCertificateChain(String arg0) {
+            return null;
+        }
+
+        public Date engineGetCreationDate(String arg0) {
+            return null;
+        }
+
+        public Key engineGetKey(String arg0, char[] arg1)
+                throws NoSuchAlgorithmException, UnrecoverableKeyException {
+            return null;
+        }
+
+        public boolean engineIsCertificateEntry(String arg0) {
+            return false;
+        }
+
+        public boolean engineIsKeyEntry(String arg0) {
+            return false;
+        }
+
+        public void engineLoad(InputStream arg0, char[] arg1)
+                throws IOException, NoSuchAlgorithmException,
+                CertificateException {
+            return;
+        }
+
+        public void engineSetCertificateEntry(String arg0, Certificate arg1)
+                throws KeyStoreException {
+            return;
+        }
+
+        public void engineSetKeyEntry(String arg0, byte[] arg1,
+                Certificate[] arg2) throws KeyStoreException {
+            return;
+        }
+
+        public void engineSetKeyEntry(String arg0, Key arg1, char[] arg2,
+                Certificate[] arg3) throws KeyStoreException {
+            return;
+        }
+
+        public int engineSize() {
+            return 0;
+        }
+
+        public void engineStore(KeyStore.LoadStoreParameter param){
+            return;
+        }
+
+        public void engineStore(OutputStream arg0, char[] arg1)
+                throws IOException, NoSuchAlgorithmException,
+                CertificateException {
+            return;
+        }        
+    }    
+
+}
+
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreBuilderTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreBuilderTest.java
new file mode 100644
index 0000000..19f6398
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreBuilderTest.java
@@ -0,0 +1,524 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.Security;
+import java.security.cert.CertificateException;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Enumeration;
+
+import org.apache.harmony.security.tests.support.KeyStoreTestSupport;
+import org.apache.harmony.security.tests.support.tmpCallbackHandler;
+
+import junit.framework.TestCase;
+
+public class KeyStoreBuilderTest extends TestCase {
+
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    private static char[] pass = { 's', 't', 'o', 'r', 'e', 'p', 'w', 'd' };
+
+    private KeyStore.PasswordProtection protPass = new KeyStore.PasswordProtection(
+            pass);
+
+    private tmpCallbackHandler tmpCall = new tmpCallbackHandler();
+
+    private KeyStore.CallbackHandlerProtection callbackHand = new KeyStore.CallbackHandlerProtection(
+            tmpCall);
+
+    private myProtectionParameter myProtParam = new myProtectionParameter(
+            new byte[5]);
+
+    public static String[] validValues = KeyStoreTestSupport.validValues;
+
+    private static String defaultType = KeyStoreTestSupport.defaultType;
+
+
+    private static Provider defaultProvider = null;
+
+    static {
+        defaultProvider = Security.getProviders("KeyFactory.DSA")[0];
+    }
+
+    /*
+     * test for method newInstance(KeyStore, KeyStore.ProtectionParameter) 
+     */
+    public void testConstructor() {
+        try {
+            new KeyStoreBuilder();
+        } catch (Exception e) {
+            fail("Unexpected exception " + e.getMessage());
+        }
+    }
+    
+    /*
+     * test for method newInstance(KeyStore, KeyStore.ProtectionParameter) 
+     */
+    public void testNewInstanceKeyStoreProtectionParameter()
+            throws KeyStoreException, NoSuchAlgorithmException, IOException,
+            CertificateException, InvalidKeyException, InvalidKeySpecException {
+        // exceptions verification
+        
+        try {
+            KeyStore.Builder.newInstance(null, null);
+            fail("NullPointerException must be thrown");
+        } catch (NullPointerException e) {
+            // expected
+        }
+        
+        try {
+            KeyStore.Builder.newInstance(null, protPass);
+            fail("NullPointerException must be thrown");
+        } catch (NullPointerException e) {
+            // expected
+        }
+        
+        KeyStore.Builder ksB;
+
+        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+        try {
+            KeyStore.Builder.newInstance(ks, null);
+            fail("NullPointerException must be thrown when ProtectionParameter is null");
+        } catch (NullPointerException e) {
+            // expected
+        }
+
+        KeyStore.PasswordProtection protPass1 = new KeyStore.PasswordProtection(
+                pass);
+        KeyStore.ProtectionParameter[] pp = { protPass, protPass1,
+                callbackHand, myProtParam };
+       for (int i = 0; i < pp.length; i++) {
+            ks = KeyStore.getInstance(KeyStore.getDefaultType());
+            try {
+                KeyStore.Builder.newInstance(ks, pp[i]);
+                fail("IllegalArgumentException must be thrown because KeyStore was not initialized");
+            } catch (IllegalArgumentException e) {
+                // expected
+            }
+            
+            ks.load(null, pass);
+            ksB = KeyStore.Builder.newInstance(ks, pp[i]);
+
+            assertEquals("Incorrect KeyStore", ksB.getKeyStore().size(), 0);
+
+            ksB = KeyStore.Builder.newInstance(ks, pp[i]);
+
+            // verification getKeyStore() and getProtectionParameter(String
+            // alias)
+            assertEquals("Incorrect KeyStore", ks, ksB.getKeyStore());
+
+            try {
+                ksB.getProtectionParameter(null);
+                fail("NullPointerException must be thrown");
+            } catch (NullPointerException e) {
+            }
+            try {
+                assertEquals(ksB.getProtectionParameter("aaa"), pp[i]);
+            } catch (KeyStoreException e) {
+                fail("Unexpected: " + e.toString() + " was thrown");
+            }
+
+            try {
+                assertEquals(ksB.getProtectionParameter("Bad alias"), pp[i]);
+            } catch (KeyStoreException e) {
+                // KeyStoreException might be thrown because there is no entry
+                // with such alias
+            }
+
+            try {
+                assertEquals(ksB.getProtectionParameter(""), pp[i]);
+            } catch (KeyStoreException e) {
+                // KeyStoreException might be thrown because there is no entry
+                // with such alias
+            }
+
+            KeyStore.ProtectionParameter pPar = ksB
+                    .getProtectionParameter("aaa");
+
+            switch (i) {
+            case 0:
+                assertTrue(pPar instanceof KeyStore.PasswordProtection);
+                break;
+            case 1:
+                assertTrue(pPar instanceof KeyStore.PasswordProtection);
+                break;
+            case 2:
+                assertTrue(pPar instanceof KeyStore.CallbackHandlerProtection);
+                break;
+            case 3:
+                assertTrue(pPar instanceof myProtectionParameter);
+                break;
+            default:
+                fail("Incorrect protection parameter");
+            }
+            assertEquals(pPar, pp[i]);
+        }
+    }
+
+    /*
+     * Test for methods: <code>newInstance(String type, Provider provider, File
+     * file, ProtectionParameter protectionParameter)</code> <code>getKeyStore()</code>
+     * <code>getProtectionParameter(String alias)</code> Assertions: throws
+     * NullPointerException if type, file or protectionParameter is null; throws
+     * IllegalArgumentException if file does not exist or is not file; throws
+     * IllegalArgumentException if ProtectionParameter is not PasswordProtection
+     * or CallbackHandlerProtection; returns new object
+     * 
+     * getKeyStore() returns specified keystore; getProtectionParameter(String
+     * alias) throws NullPointerException when alias is null; throws
+     * KeyStoreException when alias is not available; returns
+     * ProtectionParameter which is used in newInstance(...)
+     * 
+     */
+    public void testNewInstanceStringProviderFileProtectionParameter()
+            throws Exception {
+        
+        File fl = File.createTempFile("KSBuilder_ImplTest", "keystore");
+        fl.deleteOnExit();
+        KeyStore.Builder ksB;
+        KeyStore.Builder ksB1;
+        KeyStore ks = null;
+        KeyStore ks1 = null;
+
+        myProtectionParameter myPP = new myProtectionParameter(new byte[5]);
+        // check exceptions
+        try {
+
+            KeyStore.Builder.newInstance(null, defaultProvider, fl, protPass);
+            fail("NullPointerException must be thrown when type is null");
+        } catch (NullPointerException e) {
+        }
+        try {
+            KeyStore.Builder.newInstance(KeyStore.getDefaultType(), defaultProvider, null,
+                    protPass);
+            fail("NullPointerException must be thrown when file is null");
+        } catch (NullPointerException e) {
+        }
+        try {
+            KeyStore.Builder
+                    .newInstance(KeyStore.getDefaultType(), defaultProvider, fl, null);
+            fail("NullPointerException must be thrown when ProtectionParameter is null");
+        } catch (NullPointerException e) {
+        }
+        try {
+            KeyStore.Builder
+                    .newInstance(KeyStore.getDefaultType(), defaultProvider, fl, myPP);
+            fail("IllegalArgumentException must be thrown when ProtectionParameter is not correct");
+        } catch (IllegalArgumentException e) {
+        }
+        try {
+            KeyStore.Builder.newInstance(KeyStore.getDefaultType(), defaultProvider,
+                    new File(fl.getAbsolutePath().concat("should_absent")),
+                    protPass);
+            fail("IllegalArgumentException must be thrown when file does not exist");
+        } catch (IllegalArgumentException e) {
+        }
+        try {
+            // 'file' param points to directory
+            KeyStore.Builder.newInstance(KeyStore.getDefaultType(), defaultProvider, fl
+                    .getParentFile(), protPass);
+            fail("IllegalArgumentException must be thrown when file does not exist");
+        } catch (IllegalArgumentException e) {
+        }
+        ksB = KeyStore.Builder.newInstance(KeyStore.getDefaultType(), defaultProvider, fl,
+                protPass);
+        try {
+            ksB.getKeyStore();
+            fail("KeyStoreException must be throw because file is empty");
+        } catch (KeyStoreException e) {
+        }
+
+        fl = createKS();
+        KeyStore.ProtectionParameter[] pp = { myPP, protPass, callbackHand };
+        for (int i = 0; i < pp.length; i++) {
+            if (i == 0) {
+                try {
+                    KeyStore.Builder.newInstance(KeyStore.getDefaultType(), null, fl, pp[i]);
+                    fail("IllegalArgumentException must be thrown for incorrect ProtectionParameter");
+                } catch (IllegalArgumentException e) {
+                }
+                try {
+                    KeyStore.Builder.newInstance(KeyStore.getDefaultType(), defaultProvider,
+                            fl, pp[i]);
+                    fail("IllegalArgumentException must be thrown for incorrect ProtectionParameter");
+                } catch (IllegalArgumentException e) {
+                }
+                continue;
+            }
+            ksB = KeyStore.Builder.newInstance(KeyStore.getDefaultType(), null, fl, pp[i]);
+            ksB1 = KeyStore.Builder.newInstance(KeyStore.getDefaultType(), defaultProvider,
+                    fl, pp[i]);
+            try {
+                ks = ksB.getKeyStore();
+                if (i == 2) {
+                    fail("KeyStoreException must be thrown for incorrect ProtectionParameter");
+                } else {
+                    assertEquals("Incorrect KeyStore size", ks.size(), 0);
+                }
+            } catch (KeyStoreException e) {
+                if (i == 2) {
+                    continue;
+                }
+                fail("Unexpected KeyException was thrown");
+            }
+            try {
+                ks1 = ksB1.getKeyStore();
+                if (i == 2) {
+                    fail("KeyStoreException must be thrown for incorrect ProtectionParameter");
+                }
+            } catch (KeyStoreException e) {
+                if (i == 2) {
+                    continue;
+                }
+                fail("Unexpected KeyException was thrown");
+            }
+            assertEquals("Incorrect KeyStore size", ks.size(), ks1.size());
+            Enumeration iter = ks.aliases();
+            String aName;
+
+            while (iter.hasMoreElements()) {
+                aName = (String) iter.nextElement();
+                try {
+                    assertEquals("Incorrect ProtectionParameter", ksB
+                            .getProtectionParameter(aName), pp[i]);
+                } catch (Exception e) {
+                    fail("Unexpected: " + e.toString()
+                            + " was thrown for alias: " + aName);
+                }
+            }
+
+            try {
+                assertEquals(ksB.getProtectionParameter("Bad alias"), pp[i]);
+            } catch (KeyStoreException e) {
+                // KeyStoreException might be thrown because there is no entry
+                // with such alias
+            }
+
+            iter = ks1.aliases();
+            while (iter.hasMoreElements()) {
+                aName = (String) iter.nextElement();
+                assertEquals("Incorrect ProtectionParameter", ksB1
+                        .getProtectionParameter(aName), pp[i]);
+            }
+
+            try {
+                assertEquals(ksB1.getProtectionParameter("Bad alias"), pp[i]);
+            } catch (KeyStoreException e) {
+                // KeyStoreException might be thrown because there is no entry
+                // with such alias
+            }
+        }
+    }
+
+    /*
+     * Test for method: <code>newInstance(String type, Provider provider,
+     * ProtectionParameter protectionParameter)</code> <code>getKeyStore()</code>
+     * <code>getProtectionParameter(String alias)</code> Assertions: throws
+     * NullPointerException if type, or protectionParameter is null; returns new
+     * object
+     * 
+     * getKeyStore() returns empty keystore getProtectionParameter(String alias)
+     * throws NullPointerException when alias is null; throws KeyStoreException
+     * when alias is not available
+     * 
+     */
+    public void testNewInstanceStringProviderProtectionParameter()
+            throws KeyStoreException {
+        
+        try {
+            KeyStore.Builder.newInstance(null, defaultProvider, protPass);
+            fail("NullPointerException must be thrown when type is null");
+        } catch (NullPointerException e) {
+        }
+        try {
+            KeyStore.Builder.newInstance(defaultType, defaultProvider, null);
+            fail("NullPointerException must be thrown when ProtectionParameter is null");
+        } catch (NullPointerException e) {
+        }
+        myProtectionParameter myPP = new myProtectionParameter(new byte[5]);
+        KeyStore.ProtectionParameter[] pp = { protPass, myPP, callbackHand };
+        KeyStore.Builder ksB, ksB1;
+        KeyStore ks = null;
+        for (int i = 0; i < pp.length; i++) {
+            ksB = KeyStore.Builder.newInstance(defaultType, defaultProvider,
+                    pp[i]);
+            ksB1 = KeyStore.Builder.newInstance(defaultType, null, pp[i]);
+            switch (i) {
+            case 0:
+                try {
+                    ks = ksB.getKeyStore();
+                    assertNotNull("KeyStore is null", ks);
+                    try {
+                        assertEquals(ksB.getProtectionParameter("Bad alias"),
+                                pp[i]);
+                    } catch (KeyStoreException e) {
+                        // KeyStoreException might be thrown because there is no
+                        // entry with such alias
+                    }
+
+                    ks = ksB1.getKeyStore();
+                    assertNotNull("KeyStore is null", ks);
+
+                    try {
+                        assertEquals(ksB1.getProtectionParameter("Bad alias"),
+                                pp[i]);
+                    } catch (KeyStoreException e) {
+                        // KeyStoreException might be thrown because there is no
+                        // entry with such alias
+                    }
+                } catch (KeyStoreException e) {
+                    try {
+                        ks = ksB.getKeyStore();
+                    } catch (KeyStoreException e1) {
+                        assertEquals("Incorrect exception", e.getMessage(), e1
+                                .getMessage());
+                    }
+                }
+                break;
+            case 1:
+            case 2:
+                Exception ex1 = null;
+                Exception ex2 = null;
+                try {
+                    ks = ksB.getKeyStore();
+                } catch (KeyStoreException e) {
+                    ex1 = e;
+                }
+                try {
+                    ks = ksB.getKeyStore();
+                } catch (KeyStoreException e) {
+                    ex2 = e;
+                }
+                assertEquals("Incorrect exception", ex1.getMessage(), ex2
+                        .getMessage());
+
+                try {
+                    ksB.getProtectionParameter("aaa");
+                    fail("IllegalStateException must be thrown because getKeyStore() was not invoked");
+                } catch (IllegalStateException e) {
+                }
+
+                try {
+                    ks = ksB1.getKeyStore();
+                } catch (KeyStoreException e) {
+                    ex1 = e;
+                }
+                try {
+                    ks = ksB1.getKeyStore();
+                } catch (KeyStoreException e) {
+                    ex2 = e;
+                }
+                assertEquals("Incorrect exception", ex1.getMessage(), ex2
+                        .getMessage());
+
+                try {
+                    ksB1.getProtectionParameter("aaa");
+                    fail("IllegalStateException must be thrown because getKeyStore() was not invoked");
+                } catch (IllegalStateException e) {
+                }
+                break;
+
+            }
+        }
+    }
+
+    /**
+     * Additional class for creating KeyStoreBuilder
+     */
+    class myProtectionParameter implements KeyStore.ProtectionParameter {
+        public myProtectionParameter(byte[] param) {
+            if (param == null) {
+                throw new NullPointerException("param is null");
+            }
+        }
+    }
+    
+//     Creates empty KeyStore and loads it to file    
+    private File createKS() throws Exception {
+        FileOutputStream fos = null;
+        File ff = File.createTempFile("KSBuilder_ImplTest", "keystore");
+        ff.deleteOnExit();
+        try {
+
+            KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+            fos = new FileOutputStream(ff);
+            ks.load(null, null);
+            ks.store(fos, pass);
+        } finally {
+            if (fos != null) {
+                try {
+                    fos.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+        return ff;
+    }
+
+    private static class tmpPrivateKey implements PrivateKey {
+        private String alg = "My algorithm";
+
+        public String getAlgorithm() {
+            return alg;
+        }
+
+        public String getFormat() {
+            return "My Format";
+        }
+
+        public byte[] getEncoded() {
+            return new byte[1];
+        }
+
+        public tmpPrivateKey() {
+        }
+
+        public tmpPrivateKey(String algorithm) {
+            super();
+            alg = algorithm;
+        }
+    }
+    
+    class KeyStoreBuilder extends KeyStore.Builder {
+        public KeyStoreBuilder() {
+            super();
+        }
+        
+        public KeyStore getKeyStore() {
+            return null;
+        }
+        
+        public KeyStore.ProtectionParameter getProtectionParameter(String alias) {
+            return null;
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreException2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreException2Test.java
new file mode 100644
index 0000000..15e0399
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreException2Test.java
@@ -0,0 +1,44 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.KeyStoreException;
+
+public class KeyStoreException2Test extends junit.framework.TestCase {
+
+    /**
+     * @tests java.security.KeyStoreException#KeyStoreException()
+     */
+    public void test_Constructor() {
+        // Test for method java.security.KeyStoreException()
+        KeyStoreException e = new KeyStoreException();
+        assertEquals("Failed toString test for constructed instance", "java.security.KeyStoreException", e
+                .toString());
+    }
+
+    /**
+     * @tests java.security.KeyStoreException#KeyStoreException(java.lang.String)
+     */
+    public void test_ConstructorLjava_lang_String() {
+        // Test for method java.security.KeyStoreException(java.lang.String)
+        KeyStoreException e = new KeyStoreException("test message");
+        assertEquals("Failed toString test for constructed instance", 
+                        "java.security.KeyStoreException: test message", e
+                .toString());
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreExceptionTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreExceptionTest.java
new file mode 100644
index 0000000..67e7c6c
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreExceptionTest.java
@@ -0,0 +1,187 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.KeyStoreException;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>KeyStoreException</code> class constructors and methods.
+ * 
+ */
+public class KeyStoreExceptionTest extends TestCase {
+
+    public static void main(String[] args) {
+    }
+
+    /**
+     * Constructor for KeyStoreExceptionTests.
+     * 
+     * @param arg0
+     */
+    public KeyStoreExceptionTest(String arg0) {
+        super(arg0);
+    }
+
+    private static String[] msgs = {
+            "",
+            "Check new message",
+            "Check new message Check new message Check new message Check new message Check new message" };
+
+    private static Throwable tCause = new Throwable("Throwable for exception");
+
+    /**
+     * Test for <code>KeyStoreException()</code> constructor Assertion:
+     * constructs KeyStoreException with no detail message
+     */
+    public void testKeyStoreException01() {
+        KeyStoreException tE = new KeyStoreException();
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>KeyStoreException(String)</code> constructor Assertion:
+     * constructs KeyStoreException with detail message msg. Parameter
+     * <code>msg</code> is not null.
+     */
+    public void testKeyStoreException02() {
+        KeyStoreException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new KeyStoreException(msgs[i]);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+
+    /**
+     * Test for <code>KeyStoreException(String)</code> constructor Assertion:
+     * constructs KeyStoreException when <code>msg</code> is null
+     */
+    public void testKeyStoreException03() {
+        String msg = null;
+        KeyStoreException tE = new KeyStoreException(msg);
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>KeyStoreException(Throwable)</code> constructor
+     * Assertion: constructs KeyStoreException when <code>cause</code> is null
+     */
+    public void testKeyStoreException04() {
+        Throwable cause = null;
+        KeyStoreException tE = new KeyStoreException(cause);
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>KeyStoreException(Throwable)</code> constructor
+     * Assertion: constructs KeyStoreException when <code>cause</code> is not
+     * null
+     */
+    public void testKeyStoreException05() {
+        KeyStoreException tE = new KeyStoreException(tCause);
+        if (tE.getMessage() != null) {
+            String toS = tCause.toString();
+            String getM = tE.getMessage();
+            assertTrue("getMessage() should contain ".concat(toS), (getM
+                    .indexOf(toS) != -1));
+        }
+        assertNotNull("getCause() must not return null", tE.getCause());
+        assertEquals("getCause() must return ".concat(tCause.toString()), tE
+                .getCause(), tCause);
+    }
+
+    /**
+     * Test for <code>KeyStoreException(String, Throwable)</code> constructor
+     * Assertion: constructs KeyStoreException when <code>cause</code> is null
+     * <code>msg</code> is null
+     */
+    public void testKeyStoreException06() {
+        KeyStoreException tE = new KeyStoreException(null, null);
+        assertNull("getMessage() must return null", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>KeyStoreException(String, Throwable)</code> constructor
+     * Assertion: constructs KeyStoreException when <code>cause</code> is null
+     * <code>msg</code> is not null
+     */
+    public void testKeyStoreException07() {
+        KeyStoreException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new KeyStoreException(msgs[i], null);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+
+    /**
+     * Test for <code>KeyStoreException(String, Throwable)</code> constructor
+     * Assertion: constructs KeyStoreException when <code>cause</code> is not
+     * null <code>msg</code> is null
+     */
+    public void testKeyStoreException08() {
+        KeyStoreException tE = new KeyStoreException(null, tCause);
+        if (tE.getMessage() != null) {
+            String toS = tCause.toString();
+            String getM = tE.getMessage();
+            assertTrue("getMessage() must should ".concat(toS), (getM
+                    .indexOf(toS) != -1));
+        }
+        assertNotNull("getCause() must not return null", tE.getCause());
+        assertEquals("getCause() must return ".concat(tCause.toString()), tE
+                .getCause(), tCause);
+    }
+
+    /**
+     * Test for <code>KeyStoreException(String, Throwable)</code> constructor
+     * Assertion: constructs KeyStoreException when <code>cause</code> is not
+     * null <code>msg</code> is not null
+     */
+    public void testKeyStoreException09() {
+        KeyStoreException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new KeyStoreException(msgs[i], tCause);
+            String getM = tE.getMessage();
+            String toS = tCause.toString();
+            if (msgs[i].length() > 0) {
+                assertTrue("getMessage() must contain ".concat(msgs[i]), getM
+                        .indexOf(msgs[i]) != -1);
+                if (!getM.equals(msgs[i])) {
+                    assertTrue("getMessage() should contain ".concat(toS), getM
+                            .indexOf(toS) != -1);
+                }
+            }
+            assertNotNull("getCause() must not return null", tE.getCause());
+            assertEquals("getCause() must return ".concat(tCause.toString()),
+                    tE.getCause(), tCause);
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreSpiTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreSpiTest.java
new file mode 100644
index 0000000..76b2966
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreSpiTest.java
@@ -0,0 +1,273 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Vera Y. Petrashkova
+ * @version $Revision$
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.InvalidKeyException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.KeyStoreSpi;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.UnrecoverableEntryException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.util.Date;
+
+import org.apache.harmony.security.tests.support.MyKeyStoreSpi;
+import org.apache.harmony.security.tests.support.MyLoadStoreParams;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>KeyStoreSpi</code> constructor and methods
+ * 
+ */
+
+public class KeyStoreSpiTest extends TestCase {
+
+    /**
+     * Constructor for KeyStoreSpi.
+     * 
+     * @param arg0
+     */
+    public KeyStoreSpiTest(String arg0) {
+        super(arg0);
+    }
+
+    /*
+     * @tests java.security.KeyStore.engineEntryInstanceOf(String, Class<?
+     * extends Entry>)
+     */
+    public void test_engineEntryInstanceOf() throws Exception {
+
+        KeyStoreSpi ksSpi = new MyKeyStoreSpi();
+
+        assertTrue(ksSpi.engineEntryInstanceOf("test_engineEntryInstanceOf_Alias1",
+                KeyStore.PrivateKeyEntry.class));
+
+        assertFalse(ksSpi.engineEntryInstanceOf("test_engineEntryInstanceOf_Alias2",
+                KeyStore.SecretKeyEntry.class));
+        
+        assertFalse(ksSpi.engineEntryInstanceOf("test_engineEntryInstanceOf_Alias3",
+                KeyStore.TrustedCertificateEntry.class));
+
+    }
+
+    /**
+     * Test for <code>KeyStoreSpi()</code> constructor and the following
+     * methods: <code>engineLoad(KeyStore.LoadStoreParameter param)</code>
+     * <code>engineStore(KeyStore.LoadStoreParameter param)</code>
+     * <code>engineGetEntry(String alias, KeyStore.ProtectionParameter param)</code>
+     * <code>engineSetEntry(String alias, KeyStore.Entry entry, KeyStore.ProtectionParameter param)</code>
+     * Assertions: creates new KeyStoreSpi object; engineGetEntry(..) returns
+     * null entry; engineStore(..) throws UnexpectedOperationException;
+     * engineSetEntry(..) throws KeyStoreException or NullPointerException
+     */
+    public void testKeyStoteSpi01() throws IOException,
+            NoSuchAlgorithmException, CertificateException,
+            UnrecoverableEntryException, KeyStoreException {
+        KeyStoreSpi ksSpi = new MyKeyStoreSpi();
+
+        tmpEntry entry = new tmpEntry();
+        tmpProtection pPar = new tmpProtection();
+
+        try {
+            ksSpi.engineStore(null);
+        } catch (UnsupportedOperationException e) {
+        }
+        assertNull("Not null entry", ksSpi.engineGetEntry("aaa", null));
+        assertNull("Not null entry", ksSpi.engineGetEntry(null, pPar));
+        assertNull("Not null entry", ksSpi.engineGetEntry("aaa", pPar));
+
+        try {
+            ksSpi.engineSetEntry("", null, null);
+            fail("KeyStoreException or NullPointerException must be thrown");
+        } catch (KeyStoreException e) {
+        } catch (NullPointerException e) {
+        }
+
+        try {
+            ksSpi.engineSetEntry("", new KeyStore.TrustedCertificateEntry(
+                    new MyCertificate("type", new byte[0])), null);
+            fail("KeyStoreException must be thrown");
+        } catch (KeyStoreException e) {
+        }
+
+        try {
+            ksSpi.engineSetEntry("aaa", entry, null);
+            fail("KeyStoreException must be thrown");
+        } catch (KeyStoreException e) {
+        }
+    }
+
+    /**
+     * Test for <code>KeyStoreSpi()</code> constructor and abstract engine
+     * methods. Assertion: creates new KeyStoreSpi object.
+     */
+    public void testKeyStoteSpi02() throws NoSuchAlgorithmException,
+            UnrecoverableKeyException, CertificateException {
+        KeyStoreSpi ksSpi = new MyKeyStoreSpi();
+        assertNull("engineGetKey(..) must return null", ksSpi.engineGetKey("",
+                new char[0]));
+        assertNull("engineGetCertificateChain(..) must return null", ksSpi
+                .engineGetCertificateChain(""));
+        assertNull("engineGetCertificate(..) must return null", ksSpi
+                .engineGetCertificate(""));
+        assertEquals("engineGetCreationDate(..) must return Date(0)", new Date(
+                0), ksSpi.engineGetCreationDate(""));
+        try {
+            ksSpi.engineSetKeyEntry("", null, new char[0], new Certificate[0]);
+            fail("KeyStoreException must be thrown from engineSetKeyEntry(..)");
+        } catch (KeyStoreException e) {
+        }
+        try {
+            ksSpi.engineSetKeyEntry("", new byte[0], new Certificate[0]);
+            fail("KeyStoreException must be thrown from engineSetKeyEntry(..)");
+        } catch (KeyStoreException e) {
+        }
+        try {
+            ksSpi.engineSetCertificateEntry("", null);
+            fail("KeyStoreException must be thrown from engineSetCertificateEntry(..)");
+        } catch (KeyStoreException e) {
+        }
+        try {
+            ksSpi.engineDeleteEntry("");
+            fail("KeyStoreException must be thrown from engineDeleteEntry(..)");
+        } catch (KeyStoreException e) {
+        }
+        assertNull("engineAliases() must return null", ksSpi.engineAliases());
+        assertFalse("engineContainsAlias(..) must return false", ksSpi
+                .engineContainsAlias(""));
+        assertEquals("engineSize() must return 0", 0, ksSpi.engineSize());
+        try {
+            ksSpi.engineStore(null, null);
+            fail("IOException must be thrown");
+        } catch (IOException e) {
+        }
+    }
+
+    /**
+     * @tests java.security.KeyStoreSpi#engineLoad(KeyStore.LoadStoreParameter)
+     */
+    public void test_engineLoadLjava_security_KeyStore_LoadStoreParameter()
+            throws Exception {
+
+        final String msg = "error";
+
+        KeyStoreSpi ksSpi = new MyKeyStoreSpi() {
+            public void engineLoad(InputStream stream, char[] password) {
+                assertNull(stream);
+                assertNull(password);
+                throw new RuntimeException(msg);
+            }
+        };
+        try {
+            ksSpi.engineLoad(null);
+            fail("Should throw exception");
+        } catch (RuntimeException e) {
+            assertSame(msg, e.getMessage());
+        }
+
+        // test: protection parameter is null
+        try {
+            ksSpi.engineLoad(new MyLoadStoreParams(null));
+            fail("No expected UnsupportedOperationException");
+        } catch (UnsupportedOperationException e) {
+        }
+
+        // test: protection parameter is not instanceof
+        // PasswordProtection or CallbackHandlerProtection
+        try {
+            ksSpi.engineLoad(new MyLoadStoreParams(new tmpProtection()));
+            fail("No expected UnsupportedOperationException");
+        } catch (UnsupportedOperationException e) {
+        }
+    }
+
+    public static void main(String args[]) {
+        junit.textui.TestRunner.run(KeyStoreSpiTest.class);
+    }
+}
+
+/**
+ * Additional class implements KeyStore.Entry interface
+ */
+class tmpEntry implements KeyStore.Entry {
+}
+
+class tmpProtection implements KeyStore.ProtectionParameter {
+}
+
+class MyCertificate extends Certificate {
+
+    // MyCertificate encoding
+    private final byte[] encoding;
+
+    public MyCertificate(String type, byte[] encoding) {
+        super(type);
+        // don't copy to allow null parameter in test
+        this.encoding = encoding;
+    }
+
+    public byte[] getEncoded() throws CertificateEncodingException {
+        // do copy to force NPE in test
+        return encoding.clone();
+    }
+
+    public void verify(PublicKey key) throws CertificateException,
+            NoSuchAlgorithmException, InvalidKeyException,
+            NoSuchProviderException, SignatureException {
+    }
+
+    public void verify(PublicKey key, String sigProvider)
+            throws CertificateException, NoSuchAlgorithmException,
+            InvalidKeyException, NoSuchProviderException, SignatureException {
+    }
+
+    public String toString() {
+        return "[My test Certificate, type: " + getType() + "]";
+    }
+
+    public PublicKey getPublicKey() {
+        return new PublicKey() {
+            public String getAlgorithm() {
+                return "DSA";
+            }
+
+            public byte[] getEncoded() {
+                return new byte[] { (byte) 1, (byte) 2, (byte) 3 };
+            }
+
+            public String getFormat() {
+                return "TEST_FORMAT";
+            }
+        };
+    }
+
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreTest.java
new file mode 100644
index 0000000..bf70475
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreTest.java
@@ -0,0 +1,340 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.Provider;
+import java.security.Security;
+import java.security.SignatureException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.InvalidKeyException;
+import java.security.NoSuchProviderException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Set;
+import java.math.BigInteger;
+
+import org.apache.harmony.security.tests.support.KeyStoreTestSupport;
+import org.apache.harmony.security.tests.support.MyLoadStoreParams;
+import org.apache.harmony.security.tests.support.SpiEngUtils;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>KeyStore</code> constructor and methods
+ * 
+ */
+
+public class KeyStoreTest extends TestCase {
+
+    private static final String KeyStoreProviderClass = "org.apache.harmony.security.tests.support.MyKeyStore";
+
+    private static final String defaultType = "KeyStore";
+
+    public static boolean KSSupported = false;
+
+    public static String defaultProviderName = null;
+
+    public static Provider defaultProvider = null;
+
+    private static String NotSupportMsg = "Default KeyStore type is not supported";
+
+    Provider mProv;
+
+    public KeyStore[] createKS() throws Exception {
+        assertTrue(NotSupportMsg, KSSupported);
+        KeyStore[] kpg = new KeyStore[3];
+
+        kpg[0] = KeyStore.getInstance(defaultType);
+        kpg[1] = KeyStore.getInstance(defaultType, defaultProvider);
+        kpg[2] = KeyStore.getInstance(defaultType, defaultProviderName);
+        return kpg;
+    }
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        mProv = (new SpiEngUtils()).new MyProvider("MyKSProvider",
+                "Testing provider", KeyStoreTestSupport.srvKeyStore.concat(".")
+                        .concat(defaultType), KeyStoreProviderClass);
+        Security.insertProviderAt(mProv, 2);
+        defaultProvider = SpiEngUtils.isSupport(defaultType,
+                KeyStoreTestSupport.srvKeyStore);
+        KSSupported = (defaultProvider != null);
+        defaultProviderName = (KSSupported ? defaultProvider.getName() : null);
+    }
+
+    /*
+     * @see TestCase#tearDown()
+     */
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        Security.removeProvider(mProv.getName());
+    }
+
+    /**
+     * Test for <code>load(LoadStoreParameter param)</code> 
+     * <code>store(LoadStoreParameter param)</code>
+     * methods 
+     * Assertions: throw IllegalArgumentException if param is null;
+     */
+    public void testLoadStore02() throws Exception {
+        assertTrue(NotSupportMsg, KSSupported);
+
+        KeyStore[] kss = createKS();
+        assertNotNull("KeyStore objects were not created", kss);
+
+        for (int i = 0; i < kss.length; i++) {
+            try {
+                kss[i].load(null);
+                fail("IOException or IllegalArgumentException should be thrown for null parameter");
+            } catch (IOException e) {
+            } catch (IllegalArgumentException e) {
+            }
+            kss[i].load(null, null);
+            try {
+                kss[i].store(null);
+                fail("IOException or IllegalArgumentException should be thrown for null parameter");
+            } catch (IOException e) {
+            } catch (IllegalArgumentException e) {
+            }
+        }
+        KeyStore.LoadStoreParameter lParam = new MyLoadStoreParams(
+                new KeyStore.PasswordProtection(new char[0]));
+        for (int i = 0; i < kss.length; i++) {
+            kss[i].load(lParam);
+            assertEquals("Incorrect result", kss[i].size(), 0);
+            kss[i].store(lParam);
+        }
+    }
+
+    
+    /**
+     * Test for <code>setKeyEntry(String alias, byte[] key, Certificate[] chain)</code> 
+     * method 
+     * Assertion: stores KeyEntry.
+     */
+    public void testSetKeyEntry() throws Exception {
+        assertTrue(NotSupportMsg, KSSupported);
+        
+        KeyStore[] kss = createKS();
+        assertNotNull("KeyStore objects were not created", kss);
+        byte[] kk = { (byte) 1, (byte) 2, (byte) 127, (byte) 77 };
+        String alias = "keyEntry";
+        char[] pwd = new char[0];
+        byte[] res;
+        Certificate certs[] = {
+                new KeyStoreTestSupport.MCertificate(alias, kk),
+                new KeyStoreTestSupport.MCertificate(alias, kk) };
+        for (int i = 0; i < kss.length; i++) {
+            kss[i].load(null, null);
+            try {
+                kss[i].setKeyEntry("proba", null, null);
+                fail("KeyStoreException must be thrown");
+            } catch (KeyStoreException e) {
+            }
+            kss[i].setKeyEntry(alias, kk, certs);
+            res = kss[i].getKey(alias, pwd).getEncoded();
+            assertEquals(kk.length, res.length);
+            for (int j = 0; j < res.length; j++) {
+                assertEquals(res[j], kk[j]);
+            }
+            assertEquals(kss[i].getCertificateChain(alias).length, certs.length);
+            kss[i].setKeyEntry(alias, kk, null);
+            res = kss[i].getKey(alias, pwd).getEncoded();
+            assertEquals(kk.length, res.length);
+            for (int j = 0; j < res.length; j++) {
+                assertEquals(res[j], kk[j]);
+            }
+            assertNull(kss[i].getCertificateChain(alias));
+        }
+    }
+
+    /**
+     * Test for <code>getDefaultType()</code> method Assertion: returns
+     * default security key store type or "jks" string
+     */
+    public void testKeyStore01() {
+        String propName = "keystore.type";
+        String defKSType = Security.getProperty(propName);
+        String dType = KeyStore.getDefaultType();
+        String resType = defKSType;
+        if (resType == null) {
+            resType = defaultType;
+        }
+        assertNotNull("Default type have not be null", dType);
+        assertEquals("Incorrect default type", dType, resType);
+        
+        if (defKSType == null) {
+            Security.setProperty(propName, defaultType);
+            dType = KeyStore.getDefaultType();
+            resType = Security.getProperty(propName);
+            assertNotNull("Incorrect default type", resType);
+            assertNotNull("Default type have not be null", dType);
+            assertEquals("Incorrect default type", dType, resType);
+        }
+    }
+
+    /**
+     * Test for <code>getInstance(String type)</code> method 
+     * Assertion: 
+     * throws NullPointerException when type is null 
+     * throws KeyStoreException when type is not available
+     * 
+     */
+    public void testKeyStore02() throws KeyStoreException {
+        String[] invalidValues =  SpiEngUtils.invalidValues;
+        try {
+            KeyStore.getInstance(null);
+            fail("NullPointerException must be thrown when type is null");
+        } catch (NullPointerException e) {
+        }
+        for (int i = 0; i < invalidValues.length; i++) {
+            try {
+                KeyStore.getInstance(invalidValues[i]);
+                fail("KeyStoreException must be thrown (type: ".concat(
+                        invalidValues[i]).concat(" )"));
+            } catch (KeyStoreException e) {
+            }
+        }
+    }
+
+    /**
+     * @test java.security.KeyStore.PasswordProtection.getPassword()
+     */
+    public void testKeyStorePPGetPassword() {
+        // Regression for HARMONY-1539
+        // no exception expected
+        assertNull(new KeyStore.PasswordProtection(null).getPassword());
+        char[] password = new char[] {'a', 'b', 'c'};
+        KeyStore.PasswordProtection pp = new KeyStore.PasswordProtection(password);
+        assertNotSame(pp.getPassword(), password);
+        assertSame(pp.getPassword(), pp.getPassword());
+        
+    }
+
+
+    
+
+    /**
+     * @tests java.security.KeyStore.TrustedCertificateEntry.toString()
+     */
+    public void testKeyStoreTCToString() {
+           // Regression for HARMONY-1542
+           // no exception expected
+        class TestX509Certificate extends X509Certificate {
+            private static final long serialVersionUID = 1L;
+            public void checkValidity() throws CertificateExpiredException,CertificateNotYetValidException {}
+            public void checkValidity(Date p) throws CertificateExpiredException, CertificateNotYetValidException {}
+            public int getVersion() {
+                    return 0;
+            }
+            public BigInteger getSerialNumber() {
+                    return null;
+            }
+            public Principal getIssuerDN() {
+                    return null;
+            }
+            public Principal getSubjectDN() {
+                    return null;
+            }
+            public Date getNotBefore() {
+                    return null;
+            }
+            public Date getNotAfter() {
+                    return null;
+            }
+            public byte[] getTBSCertificate() throws CertificateEncodingException {
+                    return null;
+            }
+            public byte[] getSignature() {
+                    return null;
+            }
+            public String getSigAlgName() {
+                    return null;
+            }
+            public String getSigAlgOID() {
+                    return null;
+            }
+            public byte[] getSigAlgParams() {
+                    return null;
+            }
+            public boolean[] getIssuerUniqueID() {
+                    return null;
+            }
+            public boolean[] getSubjectUniqueID() {
+                    return null;
+            }
+            public boolean[] getKeyUsage() {
+                    return null;
+            }
+            public int getBasicConstraints() {
+                    return 0;
+            }
+            public byte[] getEncoded() throws CertificateEncodingException {
+                    return null;
+            }
+            public void verify(PublicKey p)
+                    throws CertificateException,
+                    NoSuchAlgorithmException,
+                    InvalidKeyException,
+                    NoSuchProviderException,
+                    SignatureException 
+            {}
+            public void verify(PublicKey p0, String p1)
+                    throws CertificateException,
+                    NoSuchAlgorithmException,
+                    InvalidKeyException,
+                    NoSuchProviderException,
+                    SignatureException 
+            {}
+            public String toString() {
+                    return null;
+            }
+            public PublicKey getPublicKey() {
+                    return null;
+            }
+            public boolean hasUnsupportedCriticalExtension() {
+                    return false;
+            }
+            public Set getCriticalExtensionOIDs() {
+                    return null;
+            }
+            public Set getNonCriticalExtensionOIDs() {
+                    return null;
+            }
+            public byte[] getExtensionValue(String p) {
+                    return null;
+            }
+        }
+        assertNotNull(new KeyStore.TrustedCertificateEntry(new TestX509Certificate()).toString());
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyTest.java
new file mode 100644
index 0000000..4f3f58a
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/KeyTest.java
@@ -0,0 +1,71 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.Key;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>Key</code> class field
+ * 
+ */
+
+public class KeyTest extends TestCase {
+
+    /**
+     * Constructor for KeyTest.
+     * 
+     * @param arg0
+     */
+    public KeyTest(String arg0) {
+        super(arg0);
+    }
+
+    /**
+     * Test for <code>serialVersionUID</code> field
+     */
+    public void testField() {
+        checkKey mk = new checkKey();
+        assertEquals("Incorrect serialVersionUID", mk.getSerVerUID(), //Key.serialVersionUID,
+                6603384152749567654L);
+    }
+    
+    public class checkKey implements Key {
+        public String getAlgorithm() {
+            return "Key";
+        }
+        public String getFormat() {
+            return "Format";
+        }
+        public byte[] getEncoded() {
+            return new byte[0];
+        }
+        public long getSerVerUID() {
+            return serialVersionUID;
+        }
+    }
+
+}
+
+
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/MessageDigest1Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/MessageDigest1Test.java
new file mode 100644
index 0000000..2c14a7d
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/MessageDigest1Test.java
@@ -0,0 +1,257 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.nio.ByteBuffer;
+import java.security.DigestException;
+import java.security.MessageDigest;
+
+import junit.framework.TestCase;
+
+import org.apache.harmony.security.tests.support.MyMessageDigest1;
+
+/**
+ * Tests for <code>MessageDigest</code> constructor and methods
+ */
+public class MessageDigest1Test extends TestCase {
+
+    /**
+     * @tests java.security.MessageDigest#reset()
+     */
+    public void test_reset() {
+        MyMessageDigest1 md = new MyMessageDigest1("ABC");
+        md.reset();
+        assertTrue(md.runEngineReset);
+    }
+
+    /**
+     * @tests java.security.MessageDigest#update(byte)
+     */
+    public void test_updateLB() {
+        MyMessageDigest1 md = new MyMessageDigest1("ABC");
+        md.update((byte) 1);
+        assertTrue(md.runEngineUpdate1);
+    }
+
+    /**
+     * @tests java.security.MessageDigest#update(byte[], int, int)
+     */
+    public void test_updateLB$LILI() {
+        MyMessageDigest1 md = new MyMessageDigest1("ABC");
+        final byte[] bytes = { 1, 2, 3, 4, 5 };
+        md.update(bytes, 1, 2);
+        assertTrue(md.runEngineUpdate2);
+
+        // Regression for HARMONY-1120
+        try {
+            // buf == null
+            md.update(null, 0, 1);
+            fail("No expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+        }
+        try {
+            // offset + len > buf.length
+            md.update(bytes, 0, bytes.length + 1);
+            fail("No expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+        }
+        try {
+            // offset + len > Integer.MAX_VALUE
+            md.update(bytes, Integer.MAX_VALUE, 1);
+            fail("No expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+        }
+        // offset<0 and len<0 are passed to provider
+        final int offset = -1;
+        final int len = -1;
+        md = new MyMessageDigest1("ABC") {
+            @Override
+            public void engineUpdate(byte[] arg0, int arg1, int arg2) {
+                assertSame("buf", bytes, arg0);
+                assertEquals("offset", offset, arg1);
+                assertEquals("len", len, arg2);
+                runEngineUpdate2 = true;
+            }
+        };
+        md.update(bytes, offset, len);
+        assertTrue(md.runEngineUpdate2);
+    }
+
+    /**
+     * @tests java.security.MessageDigest#update(byte[])
+     */
+    public void test_updateLB$() {
+        MyMessageDigest1 md = new MyMessageDigest1("ABC");
+        byte[] b = { 1, 2, 3, 4, 5 };
+        md.update(b);
+        assertTrue(md.runEngineUpdate2);
+    }
+
+    /**
+     * @tests java.security.MessageDigest#update(ByteBuffer)
+     */
+    public void test_updateLjava_nio_ByteBuffer() {
+        MyMessageDigest1 md = new MyMessageDigest1("ABC");
+        byte[] b = { 1, 2, 3, 4, 5 };
+        ByteBuffer byteBuffer = ByteBuffer.wrap(b);
+
+        int limit = byteBuffer.limit();
+        md.update(byteBuffer);
+        assertTrue(md.runEngineUpdate2);
+        assertEquals(byteBuffer.limit(), byteBuffer.position());
+        assertEquals(limit, byteBuffer.limit());
+    }
+
+    /**
+     * @tests java.security.MessageDigest#digest()
+     */
+    public void test_digest() {
+        MyMessageDigest1 md = new MyMessageDigest1("ABC");
+        assertEquals("incorrect result", 0, md.digest().length);
+        assertTrue(md.runEngineDigest);
+    }
+
+    /**
+     * @tests java.security.MessageDigest#digest(byte[])
+     */
+    public void test_digestLB$() {
+        MyMessageDigest1 md = new MyMessageDigest1("ABC");
+        byte[] b = { 1, 2, 3, 4, 5 };
+        assertEquals("incorrect result", 0, md.digest(b).length);
+        assertTrue(md.runEngineDigest);
+    }
+
+    /**
+     * @tests java.security.MessageDigest#digest(byte[], int, int)
+     */
+    public void test_digestLB$LILI() throws Exception {
+        MyMessageDigest1 md = new MyMessageDigest1("ABC");
+        byte[] b = { 1, 2, 3, 4, 5 };
+        assertEquals("incorrect result", 0, md.digest(b, 2, 3));
+        assertTrue("digest failed", md.runEngineDigest);
+
+        // Regression for Harmony-1148
+        md = new MyMessageDigest1();
+        final byte[] bytes = new byte[] { 2, 4, 1 };
+        try {
+            // buf == null
+            md.digest(null, 0, 1);
+            fail("No expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+        }
+        try {
+            // offset + len > buf.length
+            md.digest(bytes, 0, bytes.length + 1);
+            fail("No expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+        }
+        try {
+            // offset + len > Integer.MAX_VALUE
+            md.digest(bytes, Integer.MAX_VALUE, 1);
+            fail("No expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+        }
+        // offset<0 and len<0 are passed to provider
+        final int offset = -1;
+        final int len = -1;
+        final int status = 33;
+        md = new MyMessageDigest1("ABC") {
+            @Override
+            public int engineDigest(byte[] arg0, int arg1, int arg2) {
+                assertSame("buf", bytes, arg0);
+                assertEquals("offset", offset, arg1);
+                assertEquals("len", len, arg2);
+                return status;
+            }
+        };
+        assertEquals("returned status", status, md.digest(bytes, offset, len));
+    }
+
+    /**
+     * @tests java.security.MessageDigest#isEqual(byte[],byte[])
+     */
+    public void test_isEqualLB$LB$() {
+        byte[] b1 = { 1, 2, 3, 4 };
+        byte[] b2 = { 1, 2, 3, 4, 5 };
+        byte[] b3 = { 1, 3, 3, 4 };
+        byte[] b4 = { 1, 2, 3, 4 };
+
+        assertTrue(MessageDigest.isEqual(b1, b4));
+        assertFalse(MessageDigest.isEqual(b1, b2));
+        assertFalse(MessageDigest.isEqual(b1, b3));
+    }
+
+    /**
+     * @tests java.security.MessageDigest#getAlgorithm()
+     */
+    public void test_getAlgorithm() {
+        MyMessageDigest1 md = new MyMessageDigest1("ABC");
+        assertEquals("ABC", md.getAlgorithm());
+    }
+
+    /**
+     * @tests java.security.MessageDigest#getProvider()
+     */
+    public void test_getProvider() {
+        MyMessageDigest1 md = new MyMessageDigest1("ABC");
+        assertNull(md.getProvider());
+    }
+
+    /**
+     * @tests java.security.MessageDigest#getDigestLength()
+     */
+    public void test_getDigestLength() {
+        MyMessageDigest1 md = new MyMessageDigest1("ABC");
+        assertEquals(0, md.getDigestLength());
+    }
+
+    /**
+     * Tests SHA MessageDigest provider
+     */
+    public void testSHAProvider() throws Exception {
+        MessageDigest md = MessageDigest.getInstance("SHA");
+        byte[] bytes = new byte[] { 1, 1, 1, 1, 1 };
+
+        // Regression for HARMONY-1120
+        // testing combination with provider
+        try {
+            // offset < 0
+            md.update(bytes, -1, 1);
+            fail("No expected IndexOutOfBoundsException");
+        } catch (IndexOutOfBoundsException e) {
+        }
+        // No exception for len < 0
+        md.update(bytes, 1, -1);
+
+        //Regression for Harmony-1148
+        md = MessageDigest.getInstance("SHA");
+        try {
+            // offset < 0
+            md.digest(bytes, 0, -1);
+            fail("No expected DigestException");
+        } catch (DigestException e) {
+        }
+        try {
+            // len < 0
+            md.digest(bytes, -1, 0);
+            fail("No expected DigestException");
+        } catch (DigestException e) {
+        }
+
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/MessageDigest2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/MessageDigest2Test.java
new file mode 100644
index 0000000..7e043aa
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/MessageDigest2Test.java
@@ -0,0 +1,509 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.security.DigestException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.Security;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.Vector;
+
+public class MessageDigest2Test extends junit.framework.TestCase {
+
+    private static final String MESSAGEDIGEST_ID = "MessageDigest.";
+
+    private String[] digestAlgs = null;
+
+    private String providerName = null;
+
+    private static final byte[] AR1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
+
+    private static final byte[] AR2 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
+
+    private static final String MESSAGE = "abc";
+
+    private static final byte[] MESSAGE_DIGEST = { -87, -103, 62, 54, 71, 6,
+            -127, 106, -70, 62, 37, 113, 120, 80, -62, 108, -100, -48, -40,
+            -99, };
+
+    private static final byte[] MESSAGE_DIGEST_63_As = { 3, -16, -97, 91, 21,
+            -118, 122, -116, -38, -39, 32, -67, -36, 41, -72, 28, 24, -91, 81,
+            -11, };
+
+    private static final byte[] MESSAGE_DIGEST_64_As = { 0, -104, -70, -126,
+            75, 92, 22, 66, 123, -41, -95, 18, 42, 90, 68, 42, 37, -20, 100,
+            77, };
+
+    private static final byte[] MESSAGE_DIGEST_65_As = { 17, 101, 83, 38, -57,
+            8, -41, 3, 25, -66, 38, 16, -24, -91, 125, -102, 91, -107, -99, 59, };
+
+    /**
+     * @tests java.security.MessageDigest#MessageDigest(java.lang.String)
+     */
+    public void test_constructor() {
+        for (int i = 0; i < digestAlgs.length; i++) {
+            MessageDigestStub md = new MessageDigestStub(digestAlgs[i]);
+            assertEquals(digestAlgs[i], md.getAlgorithm());
+            assertEquals(0, md.getDigestLength());
+            assertNull(md.getProvider());
+        }
+    }
+    
+    /**
+     * @tests java.security.MessageDigest#clone()
+     */
+    public void test_clone() {
+        for (int i = 0; i < digestAlgs.length; i++) {
+            try {
+                MessageDigest d1 = MessageDigest.getInstance(digestAlgs[i],
+                        providerName);
+                for (byte b = 0; b < 84; b++) {
+                    d1.update(b);
+                }
+
+                MessageDigest d2 = (MessageDigest) d1.clone();
+                d1.update((byte) 1);
+                d2.update((byte) 1);
+
+                assertTrue("cloned hash differs from original for algorithm "
+                        + digestAlgs[i], MessageDigest.isEqual(d1.digest(), d2
+                        .digest()));
+            } catch (CloneNotSupportedException e) {
+                // Expected - a Signature may not be cloneable
+            } catch (NoSuchAlgorithmException e) {
+                fail("getInstance did not find algorithm " + digestAlgs[i]);
+            } catch (NoSuchProviderException e) {
+                fail("getInstance did not find provider " + providerName);
+            }
+        }
+    }
+
+    private static final byte[] SHA_DATA_2 = { 70, -54, 124, 120, -29, 57, 56,
+            119, -108, -54, -97, -76, -97, -50, -63, -73, 2, 85, -53, -79, };
+
+    private void testSerializationSHA_DATA_2(MessageDigest sha) {
+        try {
+            sha.reset();
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            DataOutputStream output = new DataOutputStream(out);
+            // -----------------------------------------------------------------------
+
+            // Made up data
+            output
+                    .writeUTF("tests.api.java.security.MessageDigestTest$InitializerFieldsTest3");
+            output.writeInt(0); // class modifiers
+            output.writeUTF("java.io.Serializable"); // interfaces
+
+            // Fields
+            output.writeUTF("sub_toBeNotSerialized"); // name
+            output.writeInt(9); // modifiers
+            output.writeUTF("Ljava/lang/String;"); // signature
+
+            output.writeUTF("sub_toBeNotSerialized2"); // name
+            output.writeInt(9); // modifiers
+            output.writeUTF("Ljava/lang/String;"); // signature
+
+            output.writeUTF("sub_toBeSerialized"); // name
+            output.writeInt(1); // modifiers
+            output.writeUTF("Ljava/lang/String;"); // signature
+
+            output.writeUTF("sub_toBeSerialized3"); // name
+            output.writeInt(1); // modifiers
+            output.writeUTF("Ljava/lang/String;"); // signature
+
+            output.writeUTF("sub_toBeSerialized4"); // name
+            output.writeInt(1); // modifiers
+            output.writeUTF("Ljava/lang/String;"); // signature
+
+            output.writeUTF("sub_toBeSerialized5"); // name
+            output.writeInt(1); // modifiers
+            output.writeUTF("Ljava/lang/String;"); // signature
+
+            // clinit
+            output.writeUTF("<clinit>"); // name
+            output.writeInt(8); // modifiers
+            output.writeUTF("()V"); // signature
+
+            // constructors
+            output.writeUTF("<init>"); // name
+            output.writeInt(0); // modifiers
+            output.writeUTF("()V"); // signature
+
+            // methods
+            output.writeUTF("equals"); // name
+            output.writeInt(1); // modifiers
+            output.writeUTF("(Ljava.lang.Object;)Z"); // signature
+
+            // -----------------------------------------------------------------------
+
+            output.flush();
+
+            byte[] data = out.toByteArray();
+            byte[] hash = sha.digest(data);
+            assertTrue("SHA_DATA_2 NOT ok", Arrays.equals(hash, SHA_DATA_2));
+        } catch (IOException e) {
+            fail("SHA_DATA_2 NOT ok");
+        }
+    }
+
+    private static final byte[] SHA_DATA_1 = { 90, 36, 111, 106, -32, 38, 4,
+            126, 21, -51, 107, 45, -64, -68, -109, 112, -31, -46, 34, 115, };
+
+    private void testSerializationSHA_DATA_1(MessageDigest sha) {
+        try {
+            sha.reset();
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            DataOutputStream output = new DataOutputStream(out);
+            // -----------------------------------------------------------------------
+
+            // Made up data
+            output
+                    .writeUTF("tests.api.java.security.MessageDigestTest$OptionalDataNotRead");
+            // name
+            output.writeInt(0); // class modifiers
+            output.writeUTF("java.io.Serializable"); // interfaces
+
+            // Fields
+            output.writeUTF("class$0"); // name
+            output.writeInt(8); // modifiers
+            output.writeUTF("Ljava/lang/Class;"); // signature
+
+            output.writeUTF("field1"); // name
+            output.writeInt(2); // modifiers
+            output.writeUTF("I"); // signature
+
+            output.writeUTF("field2"); // name
+            output.writeInt(2); // modifiers
+            output.writeUTF("I"); // signature
+
+            // clinit
+            output.writeUTF("<clinit>"); // name
+            output.writeInt(8); // modifiers
+            output.writeUTF("()V"); // signature
+
+            // constructors
+            output.writeUTF("<init>"); // name
+            output.writeInt(1); // modifiers
+            output.writeUTF("()V"); // signature
+            // -----------------------------------------------------------------------
+
+            output.flush();
+            byte[] data = out.toByteArray();
+            byte[] hash = sha.digest(data);
+            assertTrue("SHA_DATA_1 NOT ok", Arrays.equals(hash, SHA_DATA_1));
+        } catch (IOException e) {
+            fail("SHA_DATA_1 NOT ok");
+        }
+    }
+
+    /**
+     * @tests java.security.MessageDigest#digest()
+     */
+    public void test_digest() {
+        MessageDigest sha = null;
+        try {
+            sha = MessageDigest.getInstance("SHA");
+            assertNotNull(sha);
+        } catch (NoSuchAlgorithmException e) {
+            fail("getInstance did not find algorithm");
+        }
+        sha.update(MESSAGE.getBytes());
+        byte[] digest = sha.digest();
+        assertTrue("bug in SHA", MessageDigest.isEqual(digest, MESSAGE_DIGEST));
+
+        sha.reset();
+        for (int i = 0; i < 63; i++) {
+            // just under buffer capacity
+            sha.update((byte) 'a');
+        }
+        digest = sha.digest();
+        assertTrue("bug in SHA", MessageDigest.isEqual(digest,
+                MESSAGE_DIGEST_63_As));
+
+        sha.reset();
+        for (int i = 0; i < 64; i++) {
+            // exact SHA buffer capacity
+            sha.update((byte) 'a');
+        }
+        digest = sha.digest();
+        assertTrue("bug in SHA", MessageDigest.isEqual(digest,
+                MESSAGE_DIGEST_64_As));
+
+        sha.reset();
+        for (int i = 0; i < 65; i++) {
+            // just above SHA buffer capacity
+            sha.update((byte) 'a');
+        }
+        digest = sha.digest();
+        assertTrue("bug in SHA", MessageDigest.isEqual(digest,
+                MESSAGE_DIGEST_65_As));
+
+        testSerializationSHA_DATA_1(sha);
+        testSerializationSHA_DATA_2(sha);
+    }
+
+    /**
+     * @tests java.security.MessageDigest#digest(byte[])
+     */
+    public void test_digest$B() {
+        for (int i = 0; i < digestAlgs.length; i++) {
+            try {
+                MessageDigest digest = MessageDigest.getInstance(digestAlgs[i],
+                        providerName);
+                assertNotNull(digest);
+                digest.digest(AR1);
+            } catch (NoSuchAlgorithmException e) {
+                fail("getInstance did not find algorithm " + digestAlgs[i]);
+            } catch (NoSuchProviderException e) {
+                fail("getInstance did not find provider " + providerName);
+            }
+        }
+    }
+
+    /**
+     * @tests java.security.MessageDigest#digest(byte[], int, int)
+     */
+    public void test_digest$BII() {
+        for (int i = 0; i < digestAlgs.length; i++) {
+            try {
+                MessageDigest digest = MessageDigest.getInstance(digestAlgs[i],
+                        providerName);
+                assertNotNull(digest);
+                int len = digest.getDigestLength();
+                byte[] digestBytes = new byte[len];
+                digest.digest(digestBytes, 0, digestBytes.length);
+            } catch (NoSuchAlgorithmException e) {
+                fail("getInstance did not find algorithm " + digestAlgs[i]);
+            } catch (NoSuchProviderException e) {
+                fail("getInstance did not find provider " + providerName);
+            } catch (DigestException e) {
+                fail("digest caused exception for algorithm " + digestAlgs[i]
+                        + " : " + e);
+            }
+        }
+        try {
+            MessageDigest.getInstance("SHA").digest(new byte[] {},
+                    Integer.MAX_VALUE, 755);
+        } catch (NoSuchAlgorithmException e) {
+            // allowed
+        } catch (DigestException e) {
+            // allowed
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    /**
+     * @tests java.security.MessageDigest#update(byte[], int, int)
+     */
+    public void test_update$BII() {
+        try {
+            MessageDigest.getInstance("SHA").update(new byte[] {},
+                    Integer.MAX_VALUE, Integer.MAX_VALUE);
+        } catch (NoSuchAlgorithmException e) {
+            // allowed
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    /**
+     * @tests java.security.MessageDigest#getAlgorithm()
+     */
+    public void test_getAlgorithm() {
+        for (int i = 0; i < digestAlgs.length; i++) {
+            try {
+                String alg = MessageDigest.getInstance(digestAlgs[i],
+                        providerName).getAlgorithm();
+                assertTrue("getAlgorithm ok", alg.equals(digestAlgs[i]));
+            } catch (NoSuchAlgorithmException e) {
+                fail("getInstance did not find algorithm " + digestAlgs[i]);
+            } catch (NoSuchProviderException e) {
+                fail("getInstance did not find provider " + providerName);
+            }
+        }
+    }
+
+    /**
+     * @tests java.security.MessageDigest#getDigestLength()
+     */
+    public void test_getDigestLength() {
+        for (int i = 0; i < digestAlgs.length; i++) {
+            try {
+                int len = MessageDigest
+                        .getInstance(digestAlgs[i], providerName)
+                        .getDigestLength();
+                assertTrue("length not ok", len > 0);
+            } catch (NoSuchAlgorithmException e) {
+                fail("getInstance did not find algorithm " + digestAlgs[i]);
+            } catch (NoSuchProviderException e) {
+                fail("getInstance did not find provider " + providerName);
+            }
+        }// end for
+    }
+
+    /**
+     * @tests java.security.MessageDigest#getInstance(java.lang.String)
+     */
+    public void test_getInstanceLjava_lang_String() {
+        for (int i = 0; i < digestAlgs.length; i++) {
+            try {
+                MessageDigest.getInstance(digestAlgs[i]);
+            } catch (NoSuchAlgorithmException e) {
+                fail("getInstance did not find algorithm " + digestAlgs[i]);
+            }
+        }
+    }
+
+    /**
+     * @tests java.security.MessageDigest#getInstance(java.lang.String,
+     *        java.lang.String)
+     */
+    public void test_getInstanceLjava_lang_StringLjava_lang_String() {
+        for (int i = 0; i < digestAlgs.length; i++) {
+            try {
+                MessageDigest.getInstance(digestAlgs[i], providerName);
+            } catch (NoSuchAlgorithmException e) {
+                fail("getInstance did not find algorithm " + digestAlgs[i]);
+            } catch (NoSuchProviderException e) {
+                fail("getInstance did not find provider " + providerName);
+            }
+        }
+    }
+
+    /**
+     * @tests java.security.MessageDigest#getInstance(java.lang.String,
+     *        java.security.Provider)
+     */
+    public void test_getInstanceLjava_lang_StringLjava_security_Provider() {
+        Provider[] providers = Security.getProviders("MessageDigest.SHA");
+        for (int i = 0; i < digestAlgs.length; i++) {
+            for (int j = 0; j < providers.length; j++) {
+                try {
+                    MessageDigest.getInstance(digestAlgs[i], providers[j]);
+                } catch (NoSuchAlgorithmException e) {
+                    fail("getInstance did not find algorithm " + digestAlgs[i]);
+                }
+            }
+
+        }
+    }
+
+    /**
+     * @tests java.security.MessageDigest#getProvider()
+     */
+    public void test_getProvider() {
+        for (int i = 0; i < digestAlgs.length; i++) {
+            try {
+                Provider p = MessageDigest.getInstance(digestAlgs[i],
+                        providerName).getProvider();
+                assertNotNull("provider is null", p);
+            } catch (NoSuchAlgorithmException e) {
+                fail("getInstance did not find algorithm " + digestAlgs[i]);
+            } catch (NoSuchProviderException e) {
+                fail("getInstance did not find provider " + providerName);
+            }
+        }
+    }
+
+    /**
+     * @tests java.security.MessageDigest#isEqual(byte[], byte[])
+     */
+    public void test_isEqual$B$B() {
+        assertTrue("isEqual is not correct", MessageDigest.isEqual(AR1, AR2));
+    }
+
+    /**
+     * @tests java.security.MessageDigest#toString()
+     */
+    public void test_toString() {
+        try {
+            String str = MessageDigest.getInstance("SHA").toString();
+            assertNotNull("toString is null", str);
+        } catch (NoSuchAlgorithmException e) {
+            fail("getInstance did not find algorithm");
+        }
+    }
+
+    protected void setUp() {
+        if (digestAlgs == null) {
+            Provider[] providers = Security.getProviders("MessageDigest.SHA");
+            if (providers == null) {
+                fail("No providers available for test");
+            }
+
+            // Arbitrarily select the first available provider
+            providerName = providers[0].getName();
+            digestAlgs = getDigestAlgorithms(providerName);
+            if (digestAlgs == null || digestAlgs.length == 0) {
+                fail("No digest algorithms were found");
+            }
+        }
+    }
+
+    /*
+     * Returns the digest algorithms that the given provider supports.
+     */
+    private String[] getDigestAlgorithms(String providerName) {
+        Vector<String> algs = new Vector<String>();
+
+        Provider provider = Security.getProvider(providerName);
+        if (provider == null)
+            return new String[0];
+        Enumeration e = provider.keys();
+        while (e.hasMoreElements()) {
+            String algorithm = (String) e.nextElement();
+            if (algorithm.startsWith(MESSAGEDIGEST_ID)
+                    && !algorithm.contains(" ")) {
+                algs.addElement(algorithm.substring(MESSAGEDIGEST_ID.length()));
+            }
+        }// end while
+
+        return (String[]) algs.toArray(new String[algs.size()]);
+    }
+
+    private class MessageDigestStub extends MessageDigest {
+        public MessageDigestStub(String algorithm) {
+            super(algorithm);
+        }
+
+        public byte[] engineDigest() {
+            return null;
+        }
+
+        public void engineReset() {
+
+        }
+
+        public void engineUpdate(byte input) {
+
+        }
+
+        public void engineUpdate(byte[] input, int offset, int len) {
+
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/MessageDigestSpiTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/MessageDigestSpiTest.java
new file mode 100644
index 0000000..777d3e2
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/MessageDigestSpiTest.java
@@ -0,0 +1,177 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Boris V. Kuznetsov
+ * @version $Revision$
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.nio.ByteBuffer;
+import java.security.DigestException;
+import java.security.MessageDigestSpi;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>MessageDigestSpi</code> constructor and methods
+ */
+public class MessageDigestSpiTest extends TestCase {
+    
+    /**
+    * java.security.MessageDigestSpi#MessageDigestSpi()
+    */
+   public void test_constructor() {
+        try {
+            new MyMessageDigest();
+        } catch (Exception e) {
+            fail("Unexpected exception " + e.getMessage());
+        }
+    }
+
+    /**
+     * java.security.MessageDigestSpi#engineDigest(byte[], int, int)
+     */
+    public void test_engineDigestLB$LILI() throws Exception {
+
+        final int DIGEST_LENGHT = 2;
+
+        MyMessageDigest md = new MyMessageDigest() {
+
+            public int engineGetDigestLength() {
+                return DIGEST_LENGHT;
+            }
+
+            public byte[] engineDigest() {
+                return new byte[DIGEST_LENGHT]; // return non-null value
+            }
+        };
+
+        byte[] b = new byte[5];
+        try {
+            // test: null output buffer
+            md.engineDigest(null, 1, DIGEST_LENGHT);
+            fail("No expected NullPointerException");
+        } catch (NullPointerException e) {
+        }
+        try {
+            //test: len param < digest length
+            md.engineDigest(b, 1, DIGEST_LENGHT - 1);
+            fail("No expected DigestException");
+        } catch (DigestException e) {
+        }
+
+        assertEquals("incorrect result", DIGEST_LENGHT, md
+                .engineDigest(b, 1, 3));
+        
+        // Regression for HARMONY-3045
+        md = new MyMessageDigest();
+        try {
+            md.engineDigest(b, 0, 1);
+            fail("should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    /**
+     * java.security.MessageDigestSpi#engineGetDigestLength()
+     */
+    public void test_engineGetDigestLength() {
+        MyMessageDigest md = new MyMessageDigest();
+        assertEquals(0, md.engineGetDigestLength());
+    }
+
+    /**
+     * java.security.MessageDigestSpi#engineUpdate(ByteBuffer)
+     */
+    public void test_engineUpdateLjava_nio_ByteBuffer() {
+        MyMessageDigest md = new MyMessageDigest();
+        byte[] b = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+        ByteBuffer buf = ByteBuffer.wrap(b, 0, b.length);
+        buf.get(b);
+        int limit = buf.limit();
+        md.engineUpdate(buf);
+        assertEquals(limit, buf.limit());
+        assertEquals(limit, buf.position());
+
+        buf = ByteBuffer.wrap(b, 0, b.length);
+        buf.get();
+        buf.get();
+        buf.get();
+        md.engineUpdate(buf);
+        assertEquals(limit, buf.limit());
+        assertEquals(limit, buf.position());
+    }
+
+    /**
+     * @tests java.security.MessageDigestSpi#clone()
+     */
+    public void test_clone() throws CloneNotSupportedException {
+        MyMessageDigest md = new MyMessageDigest();
+        try {
+            md.clone();
+            fail("No expected CloneNotSupportedException");
+        } catch (CloneNotSupportedException e) {
+        }
+
+        MyMessageDigestCloneable mdc = new MyMessageDigestCloneable();
+        assertNotSame(mdc, mdc.clone());
+    }
+
+    private class MyMessageDigest extends MessageDigestSpi {
+
+        @Override
+        public void engineReset() {
+        }
+
+        @Override
+        public byte[] engineDigest() {
+            return null;
+        }
+
+        @Override
+        public void engineUpdate(byte arg0) {
+        }
+
+        @Override
+        public void engineUpdate(byte[] arg0, int arg1, int arg2) {
+        }
+
+        @Override
+        protected int engineDigest(byte[] buf, int offset, int len)
+                throws DigestException {
+            return super.engineDigest(buf, offset, len);
+        }
+
+        @Override
+        protected int engineGetDigestLength() {
+            return super.engineGetDigestLength();
+        }
+
+        @Override
+        protected void engineUpdate(ByteBuffer input) {
+            super.engineUpdate(input);
+        }
+    }
+
+    private class MyMessageDigestCloneable extends MyMessageDigest implements
+            Cloneable {
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/NoSuchAlgorithmException2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/NoSuchAlgorithmException2Test.java
new file mode 100644
index 0000000..5219115
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/NoSuchAlgorithmException2Test.java
@@ -0,0 +1,52 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.NoSuchAlgorithmException;
+
+public class NoSuchAlgorithmException2Test extends junit.framework.TestCase {
+
+    /**
+     * @tests java.security.NoSuchAlgorithmException#NoSuchAlgorithmException()
+     */
+    public void test_Constructor() {
+        try {
+            throw new NoSuchAlgorithmException();
+        } catch (NoSuchAlgorithmException e) {
+            assertNull("Message should be null", e.getMessage());
+            assertEquals("Unexpected toString value",
+                    "java.security.NoSuchAlgorithmException", e.toString());
+        }
+    }
+
+    /**
+     * @tests java.security.NoSuchAlgorithmException#NoSuchAlgorithmException(java.lang.String)
+     */
+    public void test_ConstructorLjava_lang_String() {
+        // Test for method
+        // java.security.NoSuchAlgorithmException(java.lang.String)
+        try {
+            throw new NoSuchAlgorithmException("Test string");
+        } catch (NoSuchAlgorithmException e) {
+            assertEquals("Wrong message", "Test string", e.getMessage());
+            assertEquals("Unexpected toString value",
+                    "java.security.NoSuchAlgorithmException: Test string", e
+                            .toString());
+        }
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/NoSuchAlgorithmExceptionTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/NoSuchAlgorithmExceptionTest.java
new file mode 100644
index 0000000..f839ba9
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/NoSuchAlgorithmExceptionTest.java
@@ -0,0 +1,190 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.NoSuchAlgorithmException;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>NoSuchAlgorithmException</code> class constructors and
+ * methods.
+ * 
+ */
+public class NoSuchAlgorithmExceptionTest extends TestCase {
+
+    public static void main(String[] args) {
+    }
+
+    /**
+     * Constructor for NoSuchAlgorithmExceptionTests.
+     * 
+     * @param arg0
+     */
+    public NoSuchAlgorithmExceptionTest(String arg0) {
+        super(arg0);
+    }
+
+    private static String[] msgs = {
+            "",
+            "Check new message",
+            "Check new message Check new message Check new message Check new message Check new message" };
+
+    private static Throwable tCause = new Throwable("Throwable for exception");
+
+    /**
+     * Test for <code>NoSuchAlgorithmException()</code> constructor Assertion:
+     * constructs NoSuchAlgorithmException with no detail message
+     */
+    public void testNoSuchAlgorithmException01() {
+        NoSuchAlgorithmException tE = new NoSuchAlgorithmException();
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>NoSuchAlgorithmException(String)</code> constructor
+     * Assertion: constructs NoSuchAlgorithmException with detail message msg.
+     * Parameter <code>msg</code> is not null.
+     */
+    public void testNoSuchAlgorithmException02() {
+        NoSuchAlgorithmException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new NoSuchAlgorithmException(msgs[i]);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+
+    /**
+     * Test for <code>NoSuchAlgorithmException(String)</code> constructor
+     * Assertion: constructs NoSuchAlgorithmException when <code>msg</code> is
+     * null
+     */
+    public void testNoSuchAlgorithmException03() {
+        String msg = null;
+        NoSuchAlgorithmException tE = new NoSuchAlgorithmException(msg);
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>NoSuchAlgorithmException(Throwable)</code> constructor
+     * Assertion: constructs NoSuchAlgorithmException when <code>cause</code>
+     * is null
+     */
+    public void testNoSuchAlgorithmException04() {
+        Throwable cause = null;
+        NoSuchAlgorithmException tE = new NoSuchAlgorithmException(cause);
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>NoSuchAlgorithmException(Throwable)</code> constructor
+     * Assertion: constructs NoSuchAlgorithmException when <code>cause</code>
+     * is not null
+     */
+    public void testNoSuchAlgorithmException05() {
+        NoSuchAlgorithmException tE = new NoSuchAlgorithmException(tCause);
+        if (tE.getMessage() != null) {
+            String toS = tCause.toString();
+            String getM = tE.getMessage();
+            assertTrue("getMessage() should contain ".concat(toS), (getM
+                    .indexOf(toS) != -1));
+        }
+        assertNotNull("getCause() must not return null", tE.getCause());
+        assertEquals("getCause() must return ".concat(tCause.toString()), tE
+                .getCause(), tCause);
+    }
+
+    /**
+     * Test for <code>NoSuchAlgorithmException(String, Throwable)</code>
+     * constructor Assertion: constructs NoSuchAlgorithmException when
+     * <code>cause</code> is null <code>msg</code> is null
+     */
+    public void testNoSuchAlgorithmException06() {
+        NoSuchAlgorithmException tE = new NoSuchAlgorithmException(null, null);
+        assertNull("getMessage() must return null", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>NoSuchAlgorithmException(String, Throwable)</code>
+     * constructor Assertion: constructs NoSuchAlgorithmException when
+     * <code>cause</code> is null <code>msg</code> is not null
+     */
+    public void testNoSuchAlgorithmException07() {
+        NoSuchAlgorithmException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new NoSuchAlgorithmException(msgs[i], null);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+
+    /**
+     * Test for <code>NoSuchAlgorithmException(String, Throwable)</code>
+     * constructor Assertion: constructs NoSuchAlgorithmException when
+     * <code>cause</code> is not null <code>msg</code> is null
+     */
+    public void testNoSuchAlgorithmException08() {
+        NoSuchAlgorithmException tE = new NoSuchAlgorithmException(null, tCause);
+        if (tE.getMessage() != null) {
+            String toS = tCause.toString();
+            String getM = tE.getMessage();
+            assertTrue("getMessage() must should ".concat(toS), (getM
+                    .indexOf(toS) != -1));
+        }
+        assertNotNull("getCause() must not return null", tE.getCause());
+        assertEquals("getCause() must return ".concat(tCause.toString()), tE
+                .getCause(), tCause);
+    }
+
+    /**
+     * Test for <code>NoSuchAlgorithmException(String, Throwable)</code>
+     * constructor Assertion: constructs NoSuchAlgorithmException when
+     * <code>cause</code> is not null <code>msg</code> is not null
+     */
+    public void testNoSuchAlgorithmException09() {
+        NoSuchAlgorithmException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new NoSuchAlgorithmException(msgs[i], tCause);
+            String getM = tE.getMessage();
+            String toS = tCause.toString();
+            if (msgs[i].length() > 0) {
+                assertTrue("getMessage() must contain ".concat(msgs[i]), getM
+                        .indexOf(msgs[i]) != -1);
+                if (!getM.equals(msgs[i])) {
+                    assertTrue("getMessage() should contain ".concat(toS), getM
+                            .indexOf(toS) != -1);
+                }
+            }
+            assertNotNull("getCause() must not return null", tE.getCause());
+            assertEquals("getCause() must return ".concat(tCause.toString()),
+                    tE.getCause(), tCause);
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/NoSuchProviderException2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/NoSuchProviderException2Test.java
new file mode 100644
index 0000000..67dc488
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/NoSuchProviderException2Test.java
@@ -0,0 +1,53 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.NoSuchProviderException;
+
+public class NoSuchProviderException2Test extends junit.framework.TestCase {
+
+    /**
+     * @tests java.security.NoSuchProviderException#NoSuchProviderException()
+     */
+    public void test_Constructor() {
+        // Test for method java.security.NoSuchProviderException()
+        try {
+            throw new NoSuchProviderException();
+        } catch (NoSuchProviderException e) {
+            assertNull("Message should be null", e.getMessage());
+            assertEquals("Unexpected toString value",
+                    "java.security.NoSuchProviderException", e.toString());
+        }
+    }
+
+    /**
+     * @tests java.security.NoSuchProviderException#NoSuchProviderException(java.lang.String)
+     */
+    public void test_ConstructorLjava_lang_String() {
+        // Test for method
+        // java.security.NoSuchProviderException(java.lang.String)
+        try {
+            throw new NoSuchProviderException("Test string");
+        } catch (NoSuchProviderException e) {
+            assertEquals("Wrong message", "Test string", e.getMessage());
+            assertEquals("Unexpected toString value",
+                    "java.security.NoSuchProviderException: Test string", e
+                            .toString());
+        }
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/NoSuchProviderExceptionTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/NoSuchProviderExceptionTest.java
new file mode 100644
index 0000000..2dfa23d
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/NoSuchProviderExceptionTest.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.NoSuchProviderException;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>NoSuchProviderException</code> class constructors and
+ * methods.
+ * 
+ */
+public class NoSuchProviderExceptionTest extends TestCase {
+
+    public static void main(String[] args) {
+    }
+
+    /**
+     * Constructor for NoSuchProviderExceptionTests.
+     * 
+     * @param arg0
+     */
+    public NoSuchProviderExceptionTest(String arg0) {
+        super(arg0);
+    }
+
+    static String[] msgs = {
+            "",
+            "Check new message",
+            "Check new message Check new message Check new message Check new message Check new message" };
+
+    static Throwable tCause = new Throwable("Throwable for exception");
+
+    /**
+     * Test for <code>NoSuchProviderException()</code> constructor Assertion:
+     * constructs NoSuchProviderException with no detail message
+     */
+    public void testNoSuchProviderException01() {
+        NoSuchProviderException tE = new NoSuchProviderException();
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>NoSuchProviderException(String)</code> constructor
+     * Assertion: constructs NoSuchProviderException with detail message msg.
+     * Parameter <code>msg</code> is not null.
+     */
+    public void testNoSuchProviderException02() {
+        NoSuchProviderException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new NoSuchProviderException(msgs[i]);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+
+    /**
+     * Test for <code>NoSuchProviderException(String)</code> constructor
+     * Assertion: constructs NoSuchProviderException when <code>msg</code> is
+     * null
+     */
+    public void testNoSuchProviderException03() {
+        String msg = null;
+        NoSuchProviderException tE = new NoSuchProviderException(msg);
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/Permission2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/Permission2Test.java
new file mode 100644
index 0000000..0ae6936
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/Permission2Test.java
@@ -0,0 +1,112 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.SecurityPermission;
+
+public class Permission2Test extends junit.framework.TestCase {
+    static class ConcretePermission extends Permission {
+        public ConcretePermission() {
+            super("noname");
+        }
+
+        public boolean equals(Object obj) {
+            return true;
+        }
+
+        public String getActions() {
+            return "none";
+        }
+
+        public int hashCode() {
+            return 1;
+        }
+
+        public boolean implies(Permission p) {
+            return true;
+        }
+    }
+
+    /**
+     * @tests java.security.Permission#Permission(java.lang.String)
+     */
+    public void test_ConstructorLjava_lang_String() {
+        // test method java.security.permission.Permission(string)
+        SecurityPermission permi = new SecurityPermission(
+                "Testing the permission abstract class");
+        String name = permi.getName();
+        assertEquals("Permission Constructor failed",
+                "Testing the permission abstract class", name);
+    }
+
+    /**
+     * @tests java.security.Permission#checkGuard(java.lang.Object)
+     */
+    public void test_checkGuardLjava_lang_Object() {
+        // test method java.security.permission.checkGuard(object)
+        SecurityPermission permi = new SecurityPermission(
+                "Testing the permission abstract class");
+        String name = permi.getName();
+        try {
+            permi.checkGuard(name);
+        } catch (SecurityException e) {
+            fail("security not granted when it is suppose to be : " + e);
+        }
+    }
+
+    /**
+     * @tests java.security.Permission#getName()
+     */
+    public void test_getName() {
+        // test method java.security.permission.getName()
+        SecurityPermission permi = new SecurityPermission("testing getName()");
+        String name = permi.getName();
+        assertEquals("getName failed to obtain the correct name",
+                "testing getName()", name);
+
+        SecurityPermission permi2 = new SecurityPermission("93048Helloworld");
+        assertEquals("getName failed to obtain correct name",
+                "93048Helloworld", permi2.getName());
+    }
+
+    /**
+     * @tests java.security.Permission#newPermissionCollection()
+     */
+    public void test_newPermissionCollection() {
+        // test method java.security.permission.newPermissionCollection
+        Permission permi = new ConcretePermission();
+        PermissionCollection permiCollect = permi.newPermissionCollection();
+        assertNull("newPermissionCollector of the abstract class "
+                + "permission did not return a null instance "
+                + "of permissionCollection", permiCollect);
+    }
+
+    /**
+     * @tests java.security.Permission#toString()
+     */
+    public void test_toString() {
+        // test method java.security.permission.toString
+        // test for permission with no action
+        SecurityPermission permi = new SecurityPermission("testing toString");
+        String toString = permi.toString();
+        assertNotNull("toString should have returned a string of elements",
+                toString);
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PermissionCollectionTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PermissionCollectionTest.java
new file mode 100644
index 0000000..2fca307
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PermissionCollectionTest.java
@@ -0,0 +1,82 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.util.*;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>PermissionCollection</code>
+ * 
+ */
+
+public class PermissionCollectionTest extends TestCase {
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(PermissionCollectionTest.class);
+    }
+
+    /**
+     * Constructor for PermissionCollectionTest.
+     * @param arg0
+     */
+    public PermissionCollectionTest(String arg0) {
+        super(arg0);
+    }
+   
+    // Bare extension to instantiate abstract PermissionCollection class
+    private static final class RealPermissionCollection extends PermissionCollection
+    {
+        final private Collection col; 
+        public RealPermissionCollection(Collection col)
+        {
+            this.col = col;            
+        }
+        
+        public void add(Permission permission) {}
+        
+        public Enumeration elements() 
+        {
+            return col == null ? null : Collections.enumeration(col);
+        }
+        
+        public boolean implies(Permission permission) 
+        {
+            return false;
+        }
+    }
+        
+    /** Test read-only flag. Should be false by default and can be set once forever. */
+    public void testReadOnly()
+    {
+        PermissionCollection pc = new RealPermissionCollection(null);
+        assertFalse("should not be read-only by default", pc.isReadOnly());
+        pc.setReadOnly();
+        assertTrue("explicitly set read-only", pc.isReadOnly());
+        pc.setReadOnly();
+        assertTrue("more calls to setReadOnly() should not harm", pc.isReadOnly());
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PermissionTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PermissionTest.java
new file mode 100644
index 0000000..054db0e
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PermissionTest.java
@@ -0,0 +1,114 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.Permission;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>Permission</code>
+ */
+
+public class PermissionTest extends TestCase {
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(PermissionTest.class);
+    }
+
+    /**
+     * Constructor for PermissionTest.
+     * 
+     * @param arg0
+     */
+    public PermissionTest(String arg0) {
+        super(arg0);
+    }
+
+    // Bare extension to instantiate abstract Permission class
+    static final class RealPermission extends Permission {
+
+        public RealPermission(String name) {
+            super(name);
+        }
+
+        public boolean equals(Object obj) {
+            return false;
+        }
+
+        public String getActions() {
+            return null;
+        }
+
+        public int hashCode() {
+            return 0;
+        }
+
+        public boolean implies(Permission permission) {
+            return false;
+        }
+    }
+
+    /**
+     * Test that a permission object is created with the specified name and is
+     * properly converted to String
+     */
+    public void testCtor() {
+        String name = "testCtor123^%$#&^ &^$";
+        Permission test = new RealPermission(name);
+        assertEquals(name, test.getName());
+        assertEquals("(" + test.getClass().getName() + " " + name + ")", test
+            .toString());
+    }
+
+    /**
+     * Test checkGuard() realization: if SecurityManager is installed, it's
+     * checkPermission() should be called with this permission, otherwise
+     * nothing happens
+     */
+    public void testCheckGuard() {
+        final Permission test = new RealPermission("234234");
+        SecurityManager old = System.getSecurityManager();
+        try {
+            System.setSecurityManager(null);
+            test.checkGuard(this);
+            final boolean[] callFlag = new boolean[] { false };
+            System.setSecurityManager(new SecurityManager() {
+
+                public void checkPermission(Permission p) {
+                    if (p == test) {
+                        callFlag[0] = true;
+                    }
+                }
+            });
+            test.checkGuard(null);
+            assertTrue(callFlag[0]);
+        } finally {
+            System.setSecurityManager(old);
+        }
+    }
+
+    /** newPermissionCollection() should return null */
+    public void testCollection() {
+        assertNull(new RealPermission("123").newPermissionCollection());
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/Permissions2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/Permissions2Test.java
new file mode 100644
index 0000000..fea99b5
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/Permissions2Test.java
@@ -0,0 +1,147 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.io.File;
+import java.io.FilePermission;
+import java.security.Permissions;
+import java.util.Enumeration;
+
+public class Permissions2Test extends junit.framework.TestCase {
+    FilePermission readAllFiles = new FilePermission("<<ALL FILES>>", "read");
+
+    FilePermission alsoReadAllFiles = new FilePermission("<<ALL FILES>>",
+            "read");
+
+    FilePermission allInCurrent = new FilePermission("*",
+            "read, write, execute,delete");
+
+    FilePermission readInCurrent = new FilePermission("*", "read");
+
+    FilePermission readInFile = new FilePermission("aFile.file", "read");
+
+    /**
+     * @tests java.security.Permissions#Permissions()
+     */
+    public void test_Constructor() {
+        // Test for method java.security.Permissions()
+        new Permissions();
+    }
+
+    /**
+     * @tests java.security.Permissions#add(java.security.Permission)
+     */
+    public void test_addLjava_security_Permission() {
+        // Test for method void
+        // java.security.Permissions.add(java.security.Permission)
+        char s = File.separatorChar;
+        FilePermission perm[] = new FilePermission[7];
+        perm[0] = readAllFiles;
+        perm[1] = allInCurrent;
+        perm[2] = new FilePermission(s + "tmp" + s + "test" + s + "*",
+                "read,write");
+        perm[3] = new FilePermission(s + "tmp" + s + "test" + s
+                + "collection.file", "read");
+        perm[4] = alsoReadAllFiles;
+        perm[5] = readInFile;
+        perm[6] = new FilePermission("hello.file", "write");
+        Permissions perms = new Permissions();
+        for (int i = 0; i < perm.length; i++) {
+            perms.add(perm[i]);
+        }
+
+        Enumeration e = perms.elements();
+        FilePermission perm2[] = new FilePermission[10];
+        int i = 0;
+        while (e.hasMoreElements()) {
+            perm2[i] = (FilePermission) e.nextElement();
+            i++;
+        }
+        assertEquals("Permissions.elements did not return the correct number "
+                + "of permission - called in add() test ", i, perm.length);
+    }
+
+    /**
+     * @tests java.security.Permissions#elements()
+     */
+    public void test_elements() {
+        // Test for method java.util.Enumeration
+        // java.security.Permissions.elements()
+        char s = File.separatorChar;
+        FilePermission perm[] = new FilePermission[7];
+        perm[0] = readAllFiles;
+        perm[1] = allInCurrent;
+        perm[2] = new FilePermission(s + "tmp" + s + "test" + s + "*",
+                "read,write");
+        perm[3] = new FilePermission(s + "tmp" + s + "test" + s
+                + "collection.file", "read");
+        perm[4] = alsoReadAllFiles;
+        perm[5] = readInFile;
+        perm[6] = new FilePermission("hello.file", "write");
+        Permissions perms = new Permissions();
+        for (int i = 0; i < perm.length; i++) {
+            perms.add(perm[i]);
+        }
+        Enumeration e = perms.elements();
+        FilePermission perm2[] = new FilePermission[10];
+        int i = 0;
+        while (e.hasMoreElements()) {
+            perm2[i] = (FilePermission) e.nextElement();
+            i++;
+        }
+        assertEquals("Permissions.elements did not return the correct "
+                + "number of permission - called in element() test", i,
+                perm.length);
+    }
+
+    /**
+     * @tests java.security.Permissions#implies(java.security.Permission)
+     */
+    public void test_impliesLjava_security_Permission() {
+        // Test for method boolean
+        // java.security.Permissions.implies(java.security.Permission)
+        char s = File.separatorChar;
+        FilePermission perm[] = new FilePermission[7];
+        perm[0] = new FilePermission("test1.file", "write");
+        perm[1] = allInCurrent;
+        perm[2] = new FilePermission(s + "tmp" + s + "test" + s + "*",
+                "read,write");
+        perm[3] = new FilePermission(s + "tmp" + s + "test" + s
+                + "collection.file", "read");
+        perm[4] = new FilePermission(s + "windows" + "*", "delete");
+        perm[5] = readInFile;
+        perm[6] = new FilePermission("hello.file", "write");
+        Permissions perms = new Permissions();
+        for (int i = 0; i < perm.length; i++) {
+            perms.add(perm[i]);
+        }
+        assertTrue("Returned true for non-subset of files", !perms
+                .implies(new FilePermission("<<ALL FILES>>", "execute")));
+        assertTrue("Returned true for non-subset of action", !perms
+                .implies(new FilePermission(s + "tmp" + s + "test" + s + "*",
+                        "execute")));
+        assertTrue("Returned false for subset of actions", perms
+                .implies(new FilePermission("*", "write")));
+        assertTrue("Returned false for subset of files", perms
+                .implies(new FilePermission(s + "tmp" + s + "test" + s
+                        + "test.file", "read")));
+        assertTrue("Returned false for subset of files and actions", perms
+                .implies(new FilePermission(s + "tmp" + s + "test" + s
+                        + "test2.file", "write")));
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PermissionsTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PermissionsTest.java
new file mode 100644
index 0000000..745cc96
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PermissionsTest.java
@@ -0,0 +1,157 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.AllPermission;
+import java.security.BasicPermission;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.SecurityPermission;
+import java.security.UnresolvedPermission;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>Permissions</code>
+ * 
+ */
+
+public class PermissionsTest extends TestCase {
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(PermissionsTest.class);
+    }
+
+    /**
+     * Can add any type of permissions. Cannot add if collection is read-only.
+     */
+    public void testAdd() {
+        Permissions ps = new Permissions();
+        Permission ap = new AllPermission();
+        Permission bp = new BasicPermission("jhb23jhg5") {
+        };
+        Permission sp0 = new SecurityPermission("abc");
+        Permission sp1 = new SecurityPermission("a.b.c");
+        Permission sp2 = new SecurityPermission("a.b.*");
+        Permission sp3 = new SecurityPermission("a.*");
+        Permission up1 = new UnresolvedPermission("131234", null, null, null);
+        Permission up2 = new UnresolvedPermission("KUJKHVKJgyuygjhb", "xcv456",
+            "26r ytf", new java.security.cert.Certificate[0]);
+        Permission[] arr = new Permission[] {
+            up1, up2, ap, bp, sp0, sp1, sp2, sp3,  };
+        for (int i = 0; i < arr.length; i++) {
+            ps.add(arr[i]);
+        }
+
+        //test add duplicate
+        ps.add(up1);
+        ps.add(sp0);
+
+        ps.setReadOnly();
+        try {
+            ps.add(up1);
+            fail("read-only flag is ignored");
+        } catch (SecurityException ok) {
+        }
+    }
+
+    /**
+     * Should return non-null empty enumeration for empty collection. For
+     * non-empty collection, should always return enumeration over unique
+     * elements.
+     */
+    public void testElements() {
+        Permissions ps = new Permissions();
+        Permission ap = new AllPermission();
+        Permission bp = new BasicPermission("jhb23jhg5") {
+
+            public PermissionCollection newPermissionCollection() {
+                return null;
+            }
+        };
+        Permission sp = new SecurityPermission("abc");
+        Permission up1 = new UnresolvedPermission("131234", null, null, null);
+        Permission up2 = new UnresolvedPermission("KUJKHVKJgyuygjhb", "xcv456",
+            "26r ytf", new java.security.cert.Certificate[0]);
+
+        Enumeration<Permission> en = ps.elements();
+        assertNotNull(en);
+        assertFalse(en.hasMoreElements());
+        
+        ps.add(up1);
+        en = ps.elements();
+        assertTrue(en.hasMoreElements());
+        assertTrue(up1.equals(en.nextElement()));
+        assertFalse(en.hasMoreElements());
+
+        ps.add(up1);
+        en = ps.elements();
+        assertTrue(en.hasMoreElements());
+        assertTrue(up1.equals(en.nextElement()));
+        //assertFalse(en.hasMoreElements());
+
+        Permission[] arr = new Permission[] {
+            ap, bp, sp, up1, up2 };
+        for (int i = 0; i < arr.length; i++) {
+            ps.add(arr[i]);
+        }
+        en = ps.elements();
+        Collection<Permission> els = new ArrayList<Permission>();
+        while (en.hasMoreElements()) {
+            els.add(en.nextElement());
+        }
+        //assertEquals(5, els.size());
+        assertTrue(els.containsAll(Arrays.asList(arr)));
+    }
+    
+     
+    /**
+     * input parameter is null 
+     */
+    public void testNull(){
+        Permissions ps = new Permissions();
+        try {
+            ps.elements().nextElement();
+            fail("should throw NoSuchElementException");
+        } catch (NoSuchElementException e) {}
+        try {
+            ps.implies(null);
+            fail("should throw NPE");
+        } catch (NullPointerException e){
+        }
+        
+        try {    
+            ps.add(null);
+            fail("should throw NullPointerException");
+        } catch (NullPointerException e){}
+
+    }
+
+ }
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PolicyTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PolicyTest.java
new file mode 100644
index 0000000..71df2ea
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PolicyTest.java
@@ -0,0 +1,351 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Alexey V. Varlamov
+ * @version $Revision$
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.io.File;
+import java.io.FilePermission;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Policy;
+import java.security.ProtectionDomain;
+import java.security.Security;
+import java.security.SecurityPermission;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashSet;
+
+import org.apache.harmony.security.tests.support.SecurityChecker;
+import org.apache.harmony.security.tests.support.TestUtils;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>Policy</code>
+ */
+public class PolicyTest extends TestCase {
+
+    public static final String JAVA_SECURITY_POLICY = "java.security.policy";
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(PolicyTest.class);
+    }
+
+    /**
+     * @tests java.security.Policy#setPolicy(java.security.Policy)
+     */
+    public void test_constructor() {
+        try {
+            new TestProvider();
+        } catch (Exception e) {
+            fail("Unexpected exception " + e.getMessage());
+        }
+    }
+
+    /**
+     * @tests java.security.Policy#setPolicy(java.security.Policy)
+     */
+    public void test_setPolicyLjava_security_Policy() {
+        SecurityManager old = System.getSecurityManager();
+        Policy oldPolicy = Policy.getPolicy();
+        try {
+            SecurityChecker checker = new SecurityChecker(
+                    new SecurityPermission("setPolicy"), true);
+            System.setSecurityManager(checker);
+            Policy custom = new TestProvider();
+            Policy.setPolicy(custom);
+            assertTrue(checker.checkAsserted);
+            assertSame(custom, Policy.getPolicy());
+
+            checker.reset();
+            checker.enableAccess = false;
+            try {
+                Policy.setPolicy(new TestProvider());
+                fail("SecurityException is intercepted");
+            } catch (SecurityException ok) {
+            }
+        } finally {
+            System.setSecurityManager(old);
+            Policy.setPolicy(oldPolicy);
+        }
+    }
+
+    /**
+     * @tests java.security.Policy#getPolicy()
+     */
+    public void test_getPolicy() {
+        SecurityManager old = System.getSecurityManager();
+        Policy oldPolicy = Policy.getPolicy();
+        try {
+            Policy.setPolicy(new TestProvider());
+            SecurityChecker checker = new SecurityChecker(
+                    new SecurityPermission("getPolicy"), true);
+            System.setSecurityManager(checker);
+            Policy.getPolicy();
+            assertTrue(checker.checkAsserted);
+
+            checker.reset();
+            checker.enableAccess = false;
+            try {
+                Policy.getPolicy();
+                fail("SecurityException is intercepted");
+            } catch (SecurityException ok) {
+            }
+        } finally {
+            System.setSecurityManager(old);
+            Policy.setPolicy(oldPolicy);
+        }
+    }
+
+    public static class TestProvider extends Policy {
+
+        PermissionCollection pc;
+
+        public PermissionCollection getPermissions(CodeSource cs) {
+            return pc;
+        }
+
+        public void refresh() {
+        }
+    }
+
+    /**
+     * Tests that getPermissions() does proper permission evaluation.
+     */
+    public void testGetPermissions() {
+        SecurityPermission sp = new SecurityPermission("abc");
+        SecurityPermission sp2 = new SecurityPermission("fbdf");
+        PermissionCollection spc = sp.newPermissionCollection();
+        spc.add(sp2);
+        ProtectionDomain pd = new ProtectionDomain(null, null);
+        ProtectionDomain pd2 = new ProtectionDomain(null, spc);
+        TestProvider policy = new TestProvider();
+        policy.pc = sp.newPermissionCollection();
+
+        // case1: empty policy, no static permissions in PD
+        PermissionCollection pc4pd = policy.getPermissions(pd);
+        assertNotNull(pc4pd);
+        Enumeration<Permission> en = pc4pd.elements();
+        assertFalse(en.hasMoreElements());
+
+        // case2: empty policy, some static permissions in PD
+        pc4pd = policy.getPermissions(pd2);
+        assertNotNull(pc4pd);
+        // no check for static permissions
+
+        // case3: non-empty policy, no static permissions in PD
+        policy.pc.add(sp);
+        pc4pd = policy.getPermissions(pd);
+        assertNotNull(pc4pd);
+        Collection<Permission> c = new HashSet<Permission>();
+        for (en = pc4pd.elements(); en.hasMoreElements(); c.add(en
+                .nextElement())) {
+        }
+
+        assertTrue(c.contains(sp));
+
+        // case4: non-empty policy, some static permissions in PD
+        pc4pd = policy.getPermissions(pd2);
+        assertNotNull(pc4pd);
+        c = new HashSet<Permission>();
+        for (en = pc4pd.elements(); en.hasMoreElements(); c.add(en
+                .nextElement())) {
+        }
+
+        assertTrue(c.contains(sp));
+        // no check for static permissions
+    }
+
+    /**
+     * @tests java.security.Policy#getPolicy()
+     * @tests java.security.Policy#setPolicy()
+     */
+    public void testResetingPolicyToDefault() {
+
+        Policy oldPolicy = Policy.getPolicy();
+        assertNotNull("Got a null system security policy", oldPolicy);
+
+        try {
+
+            Policy.setPolicy(null); // passing null resets policy
+            Policy newPolicy = Policy.getPolicy();
+
+            assertNotNull(newPolicy);
+            assertNotSame(oldPolicy, newPolicy);
+
+            assertEquals("Policy class name", Security
+                    .getProperty("policy.provider"), newPolicy.getClass()
+                    .getName());
+        } finally {
+            Policy.setPolicy(oldPolicy);
+        }
+    }
+
+    /**
+     * @tests java.security.Policy#implies(ProtectionDomain, Permission)
+     */
+    public void test_implies() {
+        Policy policy = Policy.getPolicy();
+        char s = File.separatorChar;
+
+        URL url = null;
+        try {
+            url = new URL("http://localhost");
+        } catch (MalformedURLException ex) {
+            throw new Error(ex);
+        }
+        CodeSource cs = new CodeSource(url,
+                (java.security.cert.Certificate[]) null);
+
+        FilePermission perm[] = new FilePermission[7];
+        perm[0] = new FilePermission("test1.file", "write");
+        perm[1] = new FilePermission("test1.file",
+                "read, write, execute,delete");
+        perm[2] = new FilePermission(s + "tmp" + s + "test" + s + "*",
+                "read,write");
+        perm[3] = new FilePermission(s + "tmp" + s + "test" + s
+                + "collection.file", "read");
+        perm[4] = new FilePermission(s + "windows" + "*", "delete");
+        perm[5] = new FilePermission("aFile.file", "read");
+        perm[6] = new FilePermission("hello.file", "write");
+        Permissions perms = new Permissions();
+        for (int i = 0; i < perm.length; i++) {
+            perms.add(perm[i]);
+        }
+        ProtectionDomain pd = new ProtectionDomain(cs, perms);
+
+        assertTrue(policy.implies(pd, perm[0]));
+        assertTrue(policy.implies(pd, perm[1]));
+        assertTrue(policy.implies(pd, perm[2]));
+        assertTrue(policy.implies(pd, perm[3]));
+        assertTrue(policy.implies(pd, perm[4]));
+        assertTrue(policy.implies(pd, perm[5]));
+        assertTrue(policy.implies(pd, perm[6]));
+        assertTrue(policy.implies(pd,
+                new FilePermission("test1.file", "delete")));
+        assertTrue(policy.implies(pd,
+                new FilePermission(s + "tmp" + s + "test" + s + "test1.file", "read")));
+        
+        assertFalse(policy.implies(pd, new FilePermission("aFile.file",
+                "delete")));
+        assertFalse(policy.implies(pd, new FilePermission("hello.file",
+                "delete")));
+        assertFalse(policy.implies(pd, new FilePermission(s + "tmp" + s
+                + "test" + s + "collection.file", "delete")));
+        assertFalse(policy.implies(pd, new FilePermission(s + "tmp" + s
+                + "test" + s + "*", "delete")));
+        assertFalse(policy.implies(pd, new FilePermission("hello.file",
+                "execute")));
+
+        try {
+            policy.implies(pd, null);
+            fail("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // expected
+        }
+        
+        try {
+            assertFalse(policy.implies(null, new FilePermission("test1.file", "delete")));
+        } catch (NullPointerException e) {
+            fail("Unexpected NullPointerException");
+        }
+        
+        try {
+            policy.implies(null, null);
+            fail("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    /**
+     * Test property expansion in policy files
+     */
+    public void testPropertyExpansion() throws Exception {
+
+        // Regression for HARMONY-1963 and HARMONY-2910
+        String policyFile = new File(ClassLoader.getSystemClassLoader()
+                .getResource("PolicyTest.txt").getFile()).getAbsolutePath();
+//        String policyFile = Support_Resources
+//                .getAbsoluteResourcePath("PolicyTest.txt");
+        String oldSysProp = System.getProperty(JAVA_SECURITY_POLICY);
+        Policy oldPolicy = Policy.getPolicy();
+
+        try {
+            System.setProperty(JAVA_SECURITY_POLICY, policyFile);
+
+            // test: absolute paths
+            assertCodeBasePropertyExpansion("/11111/*", "/11111/-");
+            assertCodeBasePropertyExpansion("/22222/../22222/*", "/22222/-");
+            // FIXME assertCodeBasePropertyExpansion("/33333/*",
+            // "/33333/../33333/-");
+
+            // test: relative paths
+            assertCodeBasePropertyExpansion("44444/*", "44444/-");
+            assertCodeBasePropertyExpansion("55555/../55555/*", "55555/-");
+            // FIXME assertCodeBasePropertyExpansion("66666/*",
+            // "66666/../66666/-");
+        } finally {
+            TestUtils.setSystemProperty(JAVA_SECURITY_POLICY, oldSysProp);
+            Policy.setPolicy(oldPolicy);
+        }
+    }
+
+    /**
+     * Asserts codeBase property expansion in policy file
+     * 
+     * @param codeSourceURL -
+     *            code source for policy object
+     * @param codeBaseURL -
+     *            system propery value for expansion in policy file
+     */
+    private void assertCodeBasePropertyExpansion(String codeSourceURL,
+            String codeBaseURL) throws Exception {
+
+        Policy.setPolicy(null); // reset policy
+        System.setProperty("test.bin.dir", codeBaseURL);
+
+        Policy p = Policy.getPolicy();
+        CodeSource codeSource = new CodeSource(
+                new URL("file:" + codeSourceURL),
+                (java.security.cert.Certificate[]) null);
+
+        PermissionCollection pCollection = p.getPermissions(codeSource);
+        Enumeration<Permission> elements = pCollection.elements();
+
+        SecurityPermission perm = new SecurityPermission(
+                "codeBaseForPolicyTest");
+
+        while (elements.hasMoreElements()) {
+            if (elements.nextElement().equals(perm)) {
+                return; // passed
+            }
+        }
+        fail("Failed to find SecurityPermission for codeSource="
+                + codeSourceURL + ", codeBase=" + codeBaseURL);
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PrivateKeyTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PrivateKeyTest.java
new file mode 100644
index 0000000..c0bd016
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PrivateKeyTest.java
@@ -0,0 +1,72 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.PrivateKey;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>PrivateKey</code> class field
+ * 
+ */
+
+public class PrivateKeyTest extends TestCase {
+
+    /**
+     * Constructor for PrivateKeyTest.
+     * 
+     * @param arg0
+     */
+    public PrivateKeyTest(String arg0) {
+        super(arg0);
+    }
+
+    /**
+     * Test for <code>serialVersionUID</code> field
+     */
+    public void testField() {
+        checkPrivateKey cPrKey = new checkPrivateKey(); 
+        assertEquals("Incorrect serialVersionUID", cPrKey.getSerVerUID(), //PrivateKey.serialVersionUID,
+                6034044314589513430L);
+    }
+
+    public class checkPrivateKey implements PrivateKey {
+        public String getAlgorithm() {
+            return "PublicKey";
+        }
+
+        public String getFormat() {
+            return "Format";
+        }
+
+        public byte[] getEncoded() {
+            return new byte[0];
+        }
+
+        public long getSerVerUID() {
+            return serialVersionUID;
+        }
+    }
+}
+
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PrivilegedActionException2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PrivilegedActionException2Test.java
new file mode 100644
index 0000000..24cc1a1
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PrivilegedActionException2Test.java
@@ -0,0 +1,49 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.io.IOException;
+import java.security.PrivilegedActionException;
+
+public class PrivilegedActionException2Test extends junit.framework.TestCase {
+
+    /**
+     * @tests java.security.PrivilegedActionException#PrivilegedActionException(java.lang.Exception)
+     */
+    public void test_ConstructorLjava_lang_Exception() {
+        Exception e = new Exception("test exception");
+        PrivilegedActionException pe = new PrivilegedActionException(e);
+        assertEquals("Did not encapsulate test exception!", e, pe
+                .getException());
+
+        // try it with a null exception
+        pe = new PrivilegedActionException(null);
+        assertNull("Did not encapsulate null test exception properly!", pe
+                .getException());
+    }
+
+    /**
+     * @tests java.security.PrivilegedActionException#getException()
+     */
+    public void test_getException() {
+        Exception e = new IOException("test IOException");
+        PrivilegedActionException pe = new PrivilegedActionException(e);
+        assertEquals("Did not encapsulate test IOException!", e, pe
+                .getException());
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PrivilegedActionExceptionTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PrivilegedActionExceptionTest.java
new file mode 100644
index 0000000..ea3eb1f
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PrivilegedActionExceptionTest.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Astapchuk
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.PrivilegedActionException;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit test for java.security.PrivilegedActionException.
+ * 
+ */
+
+public class PrivilegedActionExceptionTest extends TestCase {
+    /**
+     * Entry point for standalone runs.
+     * @param args command line arguments
+     */
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(PrivilegedActionExceptionTest.class);
+    }
+
+    /**
+     * Tests PrivilegedActionException(Exception)
+     */
+    public void testPrivilegedActionException() {
+        new PrivilegedActionException(null);
+        Exception ex = new Exception();
+        new PrivilegedActionException(ex);
+    }
+
+    /**
+     * Tests PrivilegedActionException.getException()
+     */
+    public void testGetException() {
+        assertNull(new PrivilegedActionException(null).getException());
+        Exception ex = new Exception();
+        assertSame(new PrivilegedActionException(ex).getException(), ex);
+    }
+
+    /**
+     * Tests PrivilegedActionException.toString()
+     */
+    public void testToString() {
+        assertNotNull(new PrivilegedActionException(null).toString());
+        assertNotNull(new PrivilegedActionException(new Exception()).toString());
+    }
+
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/ProtectionDomainTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/ProtectionDomainTest.java
new file mode 100644
index 0000000..175a953
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/ProtectionDomainTest.java
@@ -0,0 +1,276 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexander V. Astapchuk
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.net.URL;
+import java.net.MalformedURLException;
+import java.net.URLClassLoader;
+import java.security.AllPermission;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Policy;
+import java.security.Principal;
+import java.security.ProtectionDomain;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Unit tests for java.security.ProtectionDomain.
+ * 
+ */
+
+public class ProtectionDomainTest extends TestCase {
+
+    /**
+     * Entry point for standalone runs.
+     * @param args command line arguments
+     */
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(ProtectionDomainTest.class);
+    }
+
+    private final AllPermission allperm = new AllPermission();
+
+    private URL url = null;
+
+    private CodeSource cs = null;
+
+    private PermissionCollection perms = null;
+
+    private ClassLoader classldr = null;
+
+    private Principal[] principals = null; // changed in setUp()
+
+    /*
+     * @see TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+        super.setUp();
+        try {
+            url = new URL("http://localhost");
+        } catch (MalformedURLException ex) {
+            throw new Error(ex);
+        }
+        cs = new CodeSource(url, (java.security.cert.Certificate[]) null);
+        perms = allperm.newPermissionCollection();
+        perms.add(allperm);
+        classldr = URLClassLoader.newInstance(new URL[] { url });
+        principals = new Principal[] { new TestPrincipal("0"),
+                new TestPrincipal("1"), new TestPrincipal("2"),
+                new TestPrincipal("3"), new TestPrincipal("4"), };
+    }
+
+    /**
+     * Class under test for void ProtectionDomain(CodeSource,
+     * PermissionCollection)
+     */
+    public void testProtectionDomainCodeSourcePermissionCollection_00() {
+        new ProtectionDomain(null, null);
+        new ProtectionDomain(cs, null);
+
+        new ProtectionDomain(cs, perms);
+    }
+
+    /**
+     * the ctor must set the PermissionCollection read-only
+     */
+    public void testProtectionDomainCodeSourcePermissionCollection_01() {
+        assertFalse(perms.isReadOnly());
+        new ProtectionDomain(null, perms);
+        assertTrue(perms.isReadOnly());
+    }
+
+    /**
+     * Test for ProtectionDomain(CodeSource, PermissionCollection, ClassLoader, Principal[])
+     */
+    public void testProtectionDomainCodeSourcePermissionCollectionClassLoaderPrincipalArray() {
+        new ProtectionDomain(null, null, null, null);
+
+        new ProtectionDomain(cs, null, null, null);
+        new ProtectionDomain(null, perms, null, null);
+        new ProtectionDomain(null, null, classldr, null);
+        new ProtectionDomain(null, null, null, principals);
+
+        new ProtectionDomain(cs, perms, classldr, principals);
+    }
+
+    /**
+     * Tests for ProtectionDomain.getClassLoader()
+     */
+    public void testGetClassLoader() {
+        assertNull(new ProtectionDomain(null, null).getClassLoader());
+        assertSame(new ProtectionDomain(null, null, classldr, null)
+                .getClassLoader(), classldr);
+    }
+
+    /**
+     * Tests for ProtectionDomain.getCodeSource()
+     */
+    public void testGetCodeSource() {
+        assertNull(new ProtectionDomain(null, null).getCodeSource());
+        assertSame(new ProtectionDomain(cs, null).getCodeSource(), cs);
+    }
+
+    /**
+     * Tests for ProtectionDomain.getPermissions()
+     */
+    public void testGetPermissions() {
+        assertNull(new ProtectionDomain(null, null).getPermissions());
+        assertSame(new ProtectionDomain(null, perms).getPermissions(), perms);
+    }
+
+    /**
+     * getPrincipals() always returns non null array
+     */
+    public void testGetPrincipals_00() {
+        assertNotNull(new ProtectionDomain(null, null).getPrincipals());
+    }
+
+    /**
+     * getPrincipals() returns new array each time it's called
+     */
+    public void testGetPrincipals_01() {
+        ProtectionDomain pd = new ProtectionDomain(null, null, null, principals);
+        Principal[] got = pd.getPrincipals();
+        assertNotNull(got);
+        assertNotSame(got, principals);
+        assertNotSame(got, pd.getPrincipals());
+        assertTrue(got.length == principals.length);
+    }
+
+    /**
+     * ProtectionDomain with null Permissions must not imply() permissions.
+     */
+    public void testImplies_00() {
+        assertFalse(new ProtectionDomain(null, null).implies(allperm));
+    }
+
+    /**
+     * ProtectionDomain with PermissionCollection which contains AllPermission
+     * must imply() AllPermission.
+     */
+    public void testImplies_01() {
+        assertTrue(new ProtectionDomain(null, perms).implies(allperm));
+    }
+
+    /**
+     * ProtectionDomain created with a static set of permissions must not query 
+     * policy. 
+     */
+    public void testImplies_02() {
+        TestPolicy policy = new TestPolicy();
+        // null set of permissions [must] force the PD to use Policy - for 
+        // dynamic permissions
+        ProtectionDomain pd = new ProtectionDomain(cs, null);
+        policy.setTrackPD(pd);
+        try {
+            Policy.setPolicy(policy);
+            pd.implies(allperm);
+        } finally {
+            Policy.setPolicy(null);
+        }
+        assertFalse(policy.getPdTracked());
+    }
+
+    /**
+     * ProtectionDomain created with dynamic set of permissions must query 
+     * policy. 
+     */
+    public void testImplies_03() {
+        TestPolicy policy = new TestPolicy();
+        ProtectionDomain pd = new ProtectionDomain(cs, null, ClassLoader
+                .getSystemClassLoader(), principals);
+        policy.setTrackPD(pd);
+        try {
+            Policy.setPolicy(policy);
+            pd.implies(allperm);
+        } finally {
+            Policy.setPolicy(null);
+        }
+        assertTrue(policy.getPdTracked());
+    }
+
+    /**
+     * Simply checks that it's working somehow
+     */
+    public void testToString() {
+        new ProtectionDomain(null, null).toString();
+        new ProtectionDomain(cs, perms).toString();
+        new ProtectionDomain(null, null, null, null).toString();
+        new ProtectionDomain(cs, perms, classldr, principals).toString();
+    }
+
+    /**
+     * Test principal used during the testing. Does nothing.
+     */
+
+    private static class TestPrincipal implements Principal {
+        private String name;
+
+        TestPrincipal(String name) {
+            this.name = name;
+        }
+
+        public String getName() {
+            return "TestPrincipal: " + name;
+        }
+    }
+
+    private static class TestPolicy extends Policy {
+        ProtectionDomain trackPD = null;
+
+        boolean pdTracked = false;
+
+        ProtectionDomain setTrackPD(ProtectionDomain pd) {
+            ProtectionDomain tmp = trackPD;
+            trackPD = pd;
+            pdTracked = false;
+            return tmp;
+        }
+
+        boolean getPdTracked() {
+            return pdTracked;
+        }
+
+        public PermissionCollection getPermissions(CodeSource cs) {
+            return new Permissions();
+        }
+
+        //        public PermissionCollection getPermissions(ProtectionDomain domain) {
+        //            return super.getPermissions(domain);
+        //        }
+        public boolean implies(ProtectionDomain domain, Permission permission) {
+            if (trackPD != null && trackPD == domain) {
+                pdTracked = true;
+            }
+            return super.implies(domain, permission);
+        }
+
+        public void refresh() {
+            // do nothing
+        }
+    }
+
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/Provider2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/Provider2Test.java
new file mode 100644
index 0000000..bbd95a5
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/Provider2Test.java
@@ -0,0 +1,127 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.Provider;
+
+public class Provider2Test extends junit.framework.TestCase {
+
+    class TestProvider extends Provider {
+        TestProvider(String name, double version, String info) {
+            super(name, version, info);
+        }
+    }
+
+    class MyEntry implements java.util.Map.Entry {
+         public Object getKey() {
+             return null;  
+         }
+
+         public Object getValue() {
+             return null;  
+         }
+
+         public Object setValue(Object value) {
+             return null;  
+         }
+    }
+    
+    TestProvider provTest = new TestProvider("provTest", 1.2,
+            "contains nothings, purely for testing the class");
+
+    
+    /**
+     * @tests java.security.Provider#entrySet()
+     */
+    public void test_entrySet() {
+        // test method of java.security.provider.entrySet
+        provTest.put("test.prop", "this is a test property");
+        try {
+            //make it compilable on 1.5
+            provTest.entrySet().add(new MyEntry());
+            fail("was able to modify the entrySet");
+        } catch (UnsupportedOperationException e) {
+            // expected
+        }
+    }
+
+    /**
+     * @tests java.security.Provider#getInfo()
+     */
+    public void test_getInfo() {
+        // test method of java.security.provider.getInfo
+        assertEquals("the information of the provider is not stored properly",
+                "contains nothings, purely for testing the class", provTest
+                        .getInfo());
+    }
+
+    /**
+     * @tests java.security.Provider#getName()
+     */
+    public void test_getName() {
+        // test method of java.security.provider.getName
+        assertEquals("the name of the provider is not stored properly",
+                "provTest", provTest.getName());
+    }
+
+    /**
+     * @tests java.security.Provider#getVersion()
+     */
+    public void test_getVersion() {
+        // test method of java.security.provider.getVersion
+        assertEquals("the version of the provider is not stored properly",
+                1.2, provTest.getVersion(), 0);
+    }
+
+    /**
+     * @tests java.security.Provider#keySet()
+     */
+    public void test_keySet() {
+        // test method of java.security.provider.keySet
+        provTest.put("test.prop", "this is a test property");
+        try {
+            provTest.keySet().add("another property key");
+            fail("was able to modify the keySet");
+        } catch (UnsupportedOperationException e) {
+            // expected
+        }
+    }
+
+    /**
+     * @tests java.security.Provider#values()
+     */
+    public void test_values() {
+        // test method of java.security.provider.values
+        provTest.put("test.prop", "this is a test property");
+        try {
+            provTest.values().add("another property value");
+            fail("was able to modify the values collection");
+        } catch (UnsupportedOperationException e) {
+            // expected
+        }
+    }
+    
+    
+    /**
+     * @tests java.security.Provider#toString()
+     */
+    public void test_toString() {
+        // Regression for HARMONY-3734
+        assertEquals("provTest version 1.2", provTest.toString());
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/ProviderException2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/ProviderException2Test.java
new file mode 100644
index 0000000..dde5259
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/ProviderException2Test.java
@@ -0,0 +1,44 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.ProviderException;
+
+public class ProviderException2Test extends junit.framework.TestCase {
+
+    /**
+     * @tests java.security.ProviderException#ProviderException()
+     */
+    public void test_Constructor() {
+        // Test for method java.security.ProviderException()
+        ProviderException e = new ProviderException();
+        assertEquals("Failed toString test for constructed instance",
+                "java.security.ProviderException", e.toString());
+    }
+
+    /**
+     * @tests java.security.ProviderException#ProviderException(java.lang.String)
+     */
+    public void test_ConstructorLjava_lang_String() {
+        // Test for method java.security.ProviderException(java.lang.String)
+        ProviderException e = new ProviderException("test message");
+        assertEquals("Failed toString test for constructed instance", 
+                        "java.security.ProviderException: test message", e
+                .toString());
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/ProviderExceptionTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/ProviderExceptionTest.java
new file mode 100644
index 0000000..9cae2b6
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/ProviderExceptionTest.java
@@ -0,0 +1,187 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.ProviderException;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>ProviderException</code> class constructors and methods.
+ * 
+ */
+public class ProviderExceptionTest extends TestCase {
+
+    public static void main(String[] args) {
+    }
+
+    /**
+     * Constructor for ProviderExceptionTests.
+     * 
+     * @param arg0
+     */
+    public ProviderExceptionTest(String arg0) {
+        super(arg0);
+    }
+
+    private static String[] msgs = {
+            "",
+            "Check new message",
+            "Check new message Check new message Check new message Check new message Check new message" };
+
+    private static Throwable tCause = new Throwable("Throwable for exception");
+
+    /**
+     * Test for <code>ProviderException()</code> constructor Assertion:
+     * constructs ProviderException with no detail message
+     */
+    public void testProviderException01() {
+        ProviderException tE = new ProviderException();
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>ProviderException(String)</code> constructor Assertion:
+     * constructs ProviderException with detail message msg. Parameter
+     * <code>msg</code> is not null.
+     */
+    public void testProviderException02() {
+        ProviderException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new ProviderException(msgs[i]);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+
+    /**
+     * Test for <code>ProviderException(String)</code> constructor Assertion:
+     * constructs ProviderException when <code>msg</code> is null
+     */
+    public void testProviderException03() {
+        String msg = null;
+        ProviderException tE = new ProviderException(msg);
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>ProviderException(Throwable)</code> constructor
+     * Assertion: constructs ProviderException when <code>cause</code> is null
+     */
+    public void testProviderException04() {
+        Throwable cause = null;
+        ProviderException tE = new ProviderException(cause);
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>ProviderException(Throwable)</code> constructor
+     * Assertion: constructs ProviderException when <code>cause</code> is not
+     * null
+     */
+    public void testProviderException05() {
+        ProviderException tE = new ProviderException(tCause);
+        if (tE.getMessage() != null) {
+            String toS = tCause.toString();
+            String getM = tE.getMessage();
+            assertTrue("getMessage() should contain ".concat(toS), (getM
+                    .indexOf(toS) != -1));
+        }
+        assertNotNull("getCause() must not return null", tE.getCause());
+        assertEquals("getCause() must return ".concat(tCause.toString()), tE
+                .getCause(), tCause);
+    }
+
+    /**
+     * Test for <code>ProviderException(String, Throwable)</code> constructor
+     * Assertion: constructs ProviderException when <code>cause</code> is null
+     * <code>msg</code> is null
+     */
+    public void testProviderException06() {
+        ProviderException tE = new ProviderException(null, null);
+        assertNull("getMessage() must return null", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>ProviderException(String, Throwable)</code> constructor
+     * Assertion: constructs ProviderException when <code>cause</code> is null
+     * <code>msg</code> is not null
+     */
+    public void testProviderException07() {
+        ProviderException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new ProviderException(msgs[i], null);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+
+    /**
+     * Test for <code>ProviderException(String, Throwable)</code> constructor
+     * Assertion: constructs ProviderException when <code>cause</code> is not
+     * null <code>msg</code> is null
+     */
+    public void testProviderException08() {
+        ProviderException tE = new ProviderException(null, tCause);
+        if (tE.getMessage() != null) {
+            String toS = tCause.toString();
+            String getM = tE.getMessage();
+            assertTrue("getMessage() must should ".concat(toS), (getM
+                    .indexOf(toS) != -1));
+        }
+        assertNotNull("getCause() must not return null", tE.getCause());
+        assertEquals("getCause() must return ".concat(tCause.toString()), tE
+                .getCause(), tCause);
+    }
+
+    /**
+     * Test for <code>ProviderException(String, Throwable)</code> constructor
+     * Assertion: constructs ProviderException when <code>cause</code> is not
+     * null <code>msg</code> is not null
+     */
+    public void testProviderException09() {
+        ProviderException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new ProviderException(msgs[i], tCause);
+            String getM = tE.getMessage();
+            String toS = tCause.toString();
+            if (msgs[i].length() > 0) {
+                assertTrue("getMessage() must contain ".concat(msgs[i]), getM
+                        .indexOf(msgs[i]) != -1);
+                if (!getM.equals(msgs[i])) {
+                    assertTrue("getMessage() should contain ".concat(toS), getM
+                            .indexOf(toS) != -1);
+                }
+            }
+            assertNotNull("getCause() must not return null", tE.getCause());
+            assertEquals("getCause() must return ".concat(tCause.toString()),
+                    tE.getCause(), tCause);
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/ProviderServiceTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/ProviderServiceTest.java
new file mode 100644
index 0000000..4ec9c30
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/ProviderServiceTest.java
@@ -0,0 +1,211 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Boris V. Kuznetsov
+ * @version $Revision$
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.Provider;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+
+import org.apache.harmony.security.tests.support.RandomImpl;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>Provider.Service</code> constructor and methods
+ * 
+ */
+public class ProviderServiceTest extends TestCase {
+
+    public void testService() {
+        Provider p = new MyProvider();
+        try {
+            new Provider.Service(null, "type", "algorithm", "className", null,
+                    null);
+            fail("provider is null: No expected NullPointerException");
+        } catch (NullPointerException e) {
+        }
+        try {
+            new Provider.Service(p, null, "algorithm", "className", null, null);
+            fail("type is null: No expected NullPointerException");
+        } catch (NullPointerException e) {
+        }
+        try {
+            new Provider.Service(p, "type", null, "className", null, null);
+            fail("algorithm is null: No expected NullPointerException");
+        } catch (NullPointerException e) {
+        }
+        try {
+            new Provider.Service(p, "type", "algorithm", null, null, null);
+            fail("className is null: No expected NullPointerException");
+        } catch (NullPointerException e) {
+        }
+
+        Provider.Service s = new Provider.Service(p, "type", "algorithm",
+                "className", null, null);
+
+        if (!s.getType().equals("type")) {
+            fail("getType() failed");
+        }
+        if (!s.getAlgorithm().equals("algorithm")) {
+            fail("getAlgorithm() failed");
+        }
+        if (s.getProvider() != p) {
+            fail("getProvider() failed");
+        }
+        if (!s.getClassName().equals("className")) {
+            fail("getClassName() failed");
+        }
+        if (!s.supportsParameter(new Object())) {
+            fail("supportsParameter() failed");
+        }
+    }
+
+    public void testGetAttribute() {
+        Provider p = new MyProvider();
+        Provider.Service s = new Provider.Service(p, "type", "algorithm",
+                "className", null, null);
+        try {
+            s.getAttribute(null);
+            fail("No expected NullPointerException");
+        } catch (NullPointerException e) {
+        }
+
+        if (s.getAttribute("aaa") != null) {
+            fail("getAttribute(aaa) failed");
+        }
+
+        HashMap<String, String> hm = new HashMap<String, String>();
+        hm.put("attribute", "value");
+        hm.put("KeySize", "1024");
+        hm.put("AAA", "BBB");
+
+        s = new Provider.Service(p, "type", "algorithm", "className", null, hm);
+        if (s.getAttribute("bbb") != null) {
+            fail("getAttribute(bbb) failed");
+        }
+        if (!s.getAttribute("attribute").equals("value")) {
+            fail("getAttribute(attribute) failed");
+        }
+        if (!s.getAttribute("KeySize").equals("1024")) {
+            fail("getAttribute(KeySize) failed");
+        }
+    }
+
+    public void testNewInstance() {
+        Provider p = new MyProvider();
+        Provider.Service s = new Provider.Service(p, "SecureRandom",
+                "algorithm", "org.apache.harmony.security.tests.support.RandomImpl", null,
+                null);
+        Object o = null;
+        try {
+            o = s.newInstance(null);
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+            fail("newInstance() failed");
+        }
+        if (!(o instanceof RandomImpl)) {
+            fail("incorrect instance");
+        }
+
+        try {
+            o = s.newInstance(new Object());
+            fail("No expected NoSuchAlgorithmException");
+        } catch (NoSuchAlgorithmException e) {
+        }
+    }
+
+    public void testGetAlgorithm() {
+        Provider p = new MyProvider();
+        Provider.Service s1 = new Provider.Service(p, "type", "algorithm",
+                "className", null, null);
+        assertTrue(s1.getAlgorithm().equals("algorithm"));
+        
+        Provider.Service s2 = new Provider.Service(p, "SecureRandom",
+                "algorithm", "tests.java.security.support.RandomImpl", null,
+                null);
+        assertTrue(s2.getAlgorithm().equals("algorithm"));
+    }
+
+    public void testGetClassName() {
+        Provider p = new MyProvider();
+        Provider.Service s1 = new Provider.Service(p, "type", "algorithm",
+                "className", null, null);
+        assertTrue(s1.getClassName().equals("className"));
+        
+        Provider.Service s2 = new Provider.Service(p, "SecureRandom",
+                "algorithm", "tests.java.security.support.RandomImpl", null,
+                null);
+        assertTrue(s2.getClassName().equals("tests.java.security.support.RandomImpl"));
+    }
+
+    public void testGetProvider() {
+        Provider p = new MyProvider();
+        Provider.Service s1 = new Provider.Service(p, "type", "algorithm",
+                "className", null, null);
+        assertTrue(s1.getProvider() == p);
+        
+        Provider.Service s2 = new Provider.Service(p, "SecureRandom",
+                "algorithm", "tests.java.security.support.RandomImpl", null,
+                null);
+        assertTrue(s2.getProvider() == p);
+    }
+
+    public void testGetType() {
+        Provider p = new MyProvider();
+        Provider.Service s1 = new Provider.Service(p, "type", "algorithm",
+                "className", null, null);
+        assertTrue(s1.getType().equals("type"));
+        
+        Provider.Service s2 = new Provider.Service(p, "SecureRandom",
+                "algorithm", "tests.java.security.support.RandomImpl", null,
+                null);
+        assertTrue(s2.getType().equals("SecureRandom"));
+    }
+
+    public void testSupportsParameter() {
+        Provider p = new MyProvider();
+        Provider.Service s1 = new Provider.Service(p, "type", "algorithm",
+                "className", null, null);
+        assertTrue(s1.supportsParameter(null));
+        assertTrue(s1.supportsParameter(new Object()));
+    }
+
+    public void testToString() {
+        Provider p = new MyProvider();
+        Provider.Service s1 = new Provider.Service(p, "type", "algorithm",
+                "className", null, null);
+        assertTrue(s1.toString().contains("type.algorithm -> className"));
+        
+        Provider.Service s2 = new Provider.Service(p, "SecureRandom",
+                "algorithm", "tests.java.security.support.RandomImpl", null,
+                null);
+        assertTrue(s2.toString().contains("SecureRandom.algorithm -> tests.java.security.support.RandomImpl"));
+    }
+
+    class MyProvider extends Provider {
+        MyProvider() {
+            super("MyProvider", 1.0, "Provider for testing");
+            put("MessageDigest.SHA-1", "SomeClassName");
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/ProviderTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/ProviderTest.java
new file mode 100644
index 0000000..827d2ba
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/ProviderTest.java
@@ -0,0 +1,565 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Boris V. Kuznetsov
+ * @version $Revision$
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.security.Provider;
+import java.security.Provider.Service;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Map.Entry;
+
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>Provider</code> constructor and methods
+ * 
+ */
+public class ProviderTest extends TestCase {
+
+    Provider p;
+
+    /*
+     * @see TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+        super.setUp();
+        p = new MyProvider();
+    }
+
+    /*
+     * Class under test for void Provider()
+     */
+    public final void testProvider() {
+        if (!p.getProperty("Provider.id name").equals(
+                String.valueOf(p.getName()))) {
+            fail("Incorrect \"Provider.id name\" value");
+        }
+        if (!p.getProperty("Provider.id version").equals(
+                String.valueOf(p.getVersion()))) {
+            fail("Incorrect \"Provider.id version\" value");
+        }
+        if (!p.getProperty("Provider.id info").equals(
+                String.valueOf(p.getInfo()))) {
+            fail("Incorrect \"Provider.id info\" value");
+        }
+        if (!p.getProperty("Provider.id className").equals(
+                p.getClass().getName())) {
+            fail("Incorrect \"Provider.id className\" value");
+        }
+    }
+
+    public final void testClear() {
+        p.clear();
+        if (p.getProperty("MessageDigest.SHA-1") != null) {
+            fail("Provider contains properties");
+        }
+    }
+
+    /*
+     * Class under test for void Provider(String, double, String)
+     */
+    public final void testProviderStringdoubleString() {
+        Provider p = new MyProvider("Provider name", 123.456, "Provider info");
+        if (!p.getName().equals("Provider name") || p.getVersion() != 123.456
+                || !p.getInfo().equals("Provider info")) {
+            fail("Incorrect values");
+        }
+    }
+
+    public final void testGetName() {
+        if (!p.getName().equals("MyProvider")) {
+            fail("Incorrect provider name");
+        }
+    }
+
+    public final void testGetVersion() {
+        if (p.getVersion() != 1.0) {
+            fail("Incorrect provider version");
+        }
+    }
+
+    public final void testGetInfo() {
+        if (!p.getInfo().equals("Provider for testing")) {
+            fail("Incorrect provider info");
+        }
+    }
+
+    /*
+     * Class under test for void putAll(Map)
+     */
+    public final void testPutAllMap() {
+        HashMap<String, String> hm = new HashMap<String, String>();
+        hm.put("MessageDigest.SHA-1", "aaa.bbb.ccc.ddd");
+        hm.put("Property 1", "value 1");
+        hm.put("serviceName.algName attrName", "attrValue");
+        hm.put("Alg.Alias.engineClassName.aliasName", "stanbdardName");
+        p.putAll(hm);
+        if (!"value 1".equals(p.getProperty("Property 1").trim())
+                || !"attrValue".equals(p.getProperty(
+                        "serviceName.algName attrName").trim())
+                || !"stanbdardName".equals(p.getProperty(
+                        "Alg.Alias.engineClassName.aliasName").trim())
+                || !"aaa.bbb.ccc.ddd".equals(p.getProperty(
+                        "MessageDigest.SHA-1").trim())) {
+            fail("Incorrect property value");
+        }
+    }
+
+    /*
+     * Class under test for Set entrySet()
+     */
+    public final void testEntrySet() {
+        p.put("MessageDigest.SHA-256", "aaa.bbb.ccc.ddd");
+
+        Set s = p.entrySet();
+        try {
+            s.clear();
+            fail("Must return unmodifiable set");
+        } catch (UnsupportedOperationException e) {
+        }
+
+        assertEquals("Incorrect set size", 8, s.size());
+
+        for (Iterator it = s.iterator(); it.hasNext();) {
+            Entry e = (Entry) it.next();
+            String key = (String) e.getKey();
+            String val = (String) e.getValue();
+            if (key.equals("MessageDigest.SHA-1")
+                    && val.equals("SomeClassName")) {
+                continue;
+            }
+            if (key.equals("Alg.Alias.MessageDigest.SHA1")
+                    && val.equals("SHA-1")) {
+                continue;
+            }
+            if (key.equals("MessageDigest.abc") && val.equals("SomeClassName")) {
+                continue;
+            }
+            if (key.equals("Provider.id className")
+                    && val.equals(p.getClass().getName())) {
+                continue;
+            }
+            if (key.equals("Provider.id name") && val.equals("MyProvider")) {
+                continue;
+            }
+            if (key.equals("MessageDigest.SHA-256")
+                    && val.equals("aaa.bbb.ccc.ddd")) {
+                continue;
+            }
+            if (key.equals("Provider.id version") && val.equals("1.0")) {
+                continue;
+            }
+            if (key.equals("Provider.id info")
+                    && val.equals("Provider for testing")) {
+                continue;
+            }
+            fail("Incorrect set");
+        }
+    }
+
+    /*
+     * Class under test for Set keySet()
+     */
+    public final void testKeySet() {
+        p.put("MessageDigest.SHA-256", "aaa.bbb.ccc.ddd");
+
+        Set s = p.keySet();
+        try {
+            s.clear();
+        } catch (UnsupportedOperationException e) {
+        }
+        Set s1 = p.keySet();
+        if ((s == s1) || s1.isEmpty()) {
+            fail("Must return unmodifiable set");
+        }
+        if (s1.size() != 8) {
+            fail("Incorrect set size");
+        }
+        if (!s1.contains("MessageDigest.SHA-256")
+                || !s1.contains("MessageDigest.SHA-1")
+                || !s1.contains("Alg.Alias.MessageDigest.SHA1")
+                || !s1.contains("MessageDigest.abc")
+                || !s1.contains("Provider.id info")
+                || !s1.contains("Provider.id className")
+                || !s1.contains("Provider.id version")
+                || !s1.contains("Provider.id name")) {
+            fail("Incorrect set");
+        }
+    }
+
+    /*
+     * Class under test for Collection values()
+     */
+    public final void testValues() {
+        p.put("MessageDigest.SHA-256", "aaa.bbb.ccc.ddd");
+
+        Collection c = p.values();
+        try {
+            c.clear();
+        } catch (UnsupportedOperationException e) {
+        }
+        Collection c1 = p.values();
+        if ((c == c1) || c1.isEmpty()) {
+            fail("Must return unmodifiable set");
+        }
+        if (c1.size() != 8) {
+            fail("Incorrect set size " + c1.size());
+        }
+        if (!c1.contains("MyProvider") || !c1.contains("aaa.bbb.ccc.ddd")
+                || !c1.contains("Provider for testing") || !c1.contains("1.0")
+                || !c1.contains("SomeClassName") || !c1.contains("SHA-1")
+                || !c1.contains(p.getClass().getName())) {
+            fail("Incorrect set");
+        }
+    }
+
+    /*
+     * Class under test for Object put(Object, Object)
+     */
+    public final void testPutObjectObject() {
+        p.put("MessageDigest.SHA-1", "aaa.bbb.ccc.ddd");
+        p.put("Type.Algorithm", "className");
+        if (!"aaa.bbb.ccc.ddd".equals(p.getProperty("MessageDigest.SHA-1")
+                .trim())) {
+            fail("Incorrect property value");
+        }
+
+        Set services = p.getServices();
+        if (services.size() != 3) {
+            fail("incorrect size");
+        }
+        for (Iterator it = services.iterator(); it.hasNext();) {
+            Provider.Service s = (Provider.Service) it.next();
+            if ("Type".equals(s.getType())
+                    && "Algorithm".equals(s.getAlgorithm())
+                    && "className".equals(s.getClassName())) {
+                continue;
+            }
+            if ("MessageDigest".equals(s.getType())
+                    && "SHA-1".equals(s.getAlgorithm())
+                    && "aaa.bbb.ccc.ddd".equals(s.getClassName())) {
+                continue;
+            }
+            if ("MessageDigest".equals(s.getType())
+                    && "abc".equals(s.getAlgorithm())
+                    && "SomeClassName".equals(s.getClassName())) {
+                continue;
+            }
+            fail("Incorrect service");
+        }
+    }
+
+    /*
+     * Class under test for Object remove(Object)
+     */
+    public final void testRemoveObject() {
+        Object o = p.remove("MessageDigest.SHA-1");
+        if (!"SomeClassName".equals(o)) {
+            fail("Incorrect return value");
+        }
+        if (p.getProperty("MessageDigest.SHA-1") != null) {
+            fail("Provider contains properties");
+        }
+        if (p.getServices().size() != 1) {
+            fail("Service not removed");
+        }
+    }
+
+    public final void testService1() {
+        p.put("MessageDigest.SHA-1", "AnotherClassName");
+        Provider.Service s = p.getService("MessageDigest", "SHA-1");
+        if (!"AnotherClassName".equals(s.getClassName())) {
+            fail("Incorrect class name " + s.getClassName());
+        }
+    }
+
+    // public final void testService2() {
+    // Provider[] pp = Security.getProviders("MessageDigest.SHA-1");
+    // if (pp == null) {
+    // return;
+    // }
+    // Provider p2 = pp[0];
+    // String old = p2.getProperty("MessageDigest.SHA-1");
+    // try {
+    // p2.put("MessageDigest.SHA-1", "AnotherClassName");
+    // Provider.Service s = p2.getService("MessageDigest", "SHA-1");
+    // if (!"AnotherClassName".equals(s.getClassName())) {
+    // fail("Incorrect class name " + s.getClassName());
+    // }
+    // try {
+    // s.newInstance(null);
+    // fail("No expected NoSuchAlgorithmException");
+    // } catch (NoSuchAlgorithmException e) {
+    // }
+    // } finally {
+    // p2.put("MessageDigest.SHA-1", old);
+    // }
+    // }
+
+    // Regression for HARMONY-2760.
+    public void testConstructor() {
+        MyProvider myProvider = new MyProvider(null, 1, null);
+        assertNull(myProvider.getName());
+        assertNull(myProvider.getInfo());
+        assertEquals("null", myProvider.getProperty("Provider.id name"));
+        assertEquals("null", myProvider.getProperty("Provider.id info"));
+    }
+
+    public final void testGetServices() {
+        MyProvider myProvider = new MyProvider(null, 1, null);
+        Set<Provider.Service> services = myProvider.getServices();
+        assertEquals(0, services.size());
+
+        Provider.Service s[] = new Provider.Service[3];
+
+        s[0] = new Provider.Service(p, "type1", "algorithm1", "className1",
+                null, null);
+        s[1] = new Provider.Service(p, "type2", "algorithm2", "className2",
+                null, null);
+        s[2] = new Provider.Service(p, "type3", "algorithm3", "className3",
+                null, null);
+        myProvider.putService(s[0]);
+        myProvider.putService(s[1]);
+        assertEquals(2, myProvider.getNumServices());
+        Set<Service> actual = myProvider.getServices();
+
+        assertTrue(actual.contains(s[0]));
+        assertTrue(actual.contains(s[1]));
+        assertTrue(!actual.contains(s[2]));
+
+        myProvider.removeService(s[1]);
+        actual = myProvider.getServices();
+        assertEquals(1, myProvider.getNumServices());
+
+        assertTrue(actual.contains(s[0]));
+        assertTrue(!actual.contains(s[1]));
+        assertTrue(!actual.contains(s[2]));
+
+        myProvider.putService(s[2]);
+        actual = myProvider.getServices();
+        assertEquals(2, myProvider.getNumServices());
+        assertTrue(actual.contains(s[0]));
+        assertTrue(!actual.contains(s[1]));
+        assertTrue(actual.contains(s[2]));
+    }
+
+    public final void testPutService() {
+        MyProvider myProvider = new MyProvider(null, 1, null);
+        Provider.Service s[] = new Provider.Service[3];
+
+        s[0] = new Provider.Service(p, "type1", "algorithm1", "className1",
+                null, null);
+        s[1] = new Provider.Service(p, "type2", "algorithm2", "className2",
+                null, null);
+        s[2] = new Provider.Service(p, "type3", "algorithm3", "className3",
+                null, null);
+        myProvider.putService(s[0]);
+        myProvider.putService(s[1]);
+        assertEquals(2, myProvider.getNumServices());
+        Set<Service> actual = myProvider.getServices();
+
+        assertTrue(actual.contains(s[0]));
+        assertTrue(actual.contains(s[1]));
+        assertTrue(!actual.contains(s[2]));
+
+        myProvider.removeService(s[1]);
+        assertEquals(1, myProvider.getNumServices());
+        actual = myProvider.getServices();
+
+        assertTrue(actual.contains(s[0]));
+        assertTrue(!actual.contains(s[1]));
+        assertTrue(!actual.contains(s[2]));
+
+        myProvider.putService(s[2]);
+        actual = myProvider.getServices();
+        assertEquals(2, myProvider.getNumServices());
+        assertTrue(actual.contains(s[0]));
+        assertTrue(!actual.contains(s[1]));
+        assertTrue(actual.contains(s[2]));
+
+        myProvider.putService(s[2]);
+        actual = myProvider.getServices();
+        assertEquals(2, myProvider.getNumServices());
+        assertTrue(actual.contains(s[0]));
+        assertTrue(!actual.contains(s[1]));
+        assertTrue(actual.contains(s[2]));
+
+        try {
+            myProvider.putService(null);
+            fail("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public final void testRemoveService() {
+        MyProvider myProvider = new MyProvider(null, 1, null);
+        try {
+            myProvider.removeService(null);
+            fail("NullPoiterException expected");
+        } catch (NullPointerException e) {
+            // expected
+        }
+
+        Provider.Service s[] = new Provider.Service[3];
+
+        s[0] = new Provider.Service(p, "type0", "algorithm0", "className0",
+                null, null);
+        s[1] = new Provider.Service(p, "type1", "algorithm1", "className1",
+                null, null);
+        s[2] = new Provider.Service(p, "type2", "algorithm2", "className2",
+                null, null);
+
+        try {
+            myProvider.removeService(s[0]);
+        } catch (NullPointerException e) {
+            fail("Unexpected exception");
+        }
+
+        myProvider.putService(s[0]);
+        myProvider.putService(s[1]);
+        myProvider.putService(s[2]);
+        assertEquals(3, myProvider.getNumServices());
+        Set<Service> actual = myProvider.getServices();
+
+        assertTrue(actual.contains(s[0]));
+        assertTrue(actual.contains(s[1]));
+        assertTrue(actual.contains(s[2]));
+
+        myProvider.removeService(s[1]);
+        assertEquals(2, myProvider.getNumServices());
+        actual = myProvider.getServices();
+
+        assertTrue(actual.contains(s[0]));
+        assertTrue(!actual.contains(s[1]));
+        assertTrue(actual.contains(s[2]));
+
+        myProvider.removeService(s[0]);
+        assertEquals(1, myProvider.getNumServices());
+        actual = myProvider.getServices();
+
+        assertTrue(!actual.contains(s[0]));
+        assertTrue(!actual.contains(s[1]));
+        assertTrue(actual.contains(s[2]));
+
+        myProvider.removeService(s[2]);
+        assertEquals(0, myProvider.getNumServices());
+        actual = myProvider.getServices();
+
+        assertTrue(!actual.contains(s[0]));
+        assertTrue(!actual.contains(s[1]));
+        assertTrue(!actual.contains(s[2]));
+
+        try {
+            myProvider.removeService(null);
+            fail("NullPoiterException expected");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    /*
+     * Class under test for void load(InputStream)
+     */
+    public final void testLoad() throws IOException {
+        InputStream is = new ByteArrayInputStream(writeProperties());
+        MyProvider myProvider = new MyProvider("name", 1, "info");
+        myProvider.load(is);
+        assertEquals("tests.security", myProvider.get("test.pkg"));
+        assertEquals("Unit Tests", myProvider.get("test.proj"));
+        assertNull(myProvider.get("#commented.entry"));
+
+        assertEquals("info", myProvider.get("Provider.id info"));
+        String className = myProvider.getClass().toString();
+        assertEquals(
+                className.substring("class ".length(), className.length()),
+                myProvider.get("Provider.id className"));
+        assertEquals("1.0", myProvider.get("Provider.id version"));
+
+        try {
+            myProvider.load(null);
+            fail("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    protected byte[] writeProperties() throws IOException {
+        ByteArrayOutputStream bout = new ByteArrayOutputStream();
+        PrintStream ps = new PrintStream(bout);
+        ps.println("#commented.entry=Bogus");
+        ps.println("test.pkg=tests.security");
+        ps.println("test.proj=Unit Tests");
+        ps.close();
+        return bout.toByteArray();
+    }
+
+    class MyProvider extends Provider {
+        private Set<Provider.Service> services = null;
+
+        MyProvider() {
+            super("MyProvider", 1.0, "Provider for testing");
+            put("MessageDigest.SHA-1", "SomeClassName");
+            put("MessageDigest.abc", "SomeClassName");
+            put("Alg.Alias.MessageDigest.SHA1", "SHA-1");
+            if (services != null) {
+                services.clear();
+            } else {
+                services = new HashSet<Service>();
+            }
+        }
+
+        MyProvider(String name, double version, String info) {
+            super(name, version, info);
+            if (services != null) {
+                services.clear();
+            } else {
+                services = new HashSet<Service>();
+            }
+        }
+
+        public void putService(Provider.Service s) {
+            super.putService(s);
+            services.add(s);
+        }
+
+        public void removeService(Provider.Service s) {
+            super.removeService(s);
+            services.remove(s);
+        }
+
+        public int getNumServices() {
+            return services.size();
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PublicKeyTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PublicKeyTest.java
new file mode 100644
index 0000000..8fc2342
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/PublicKeyTest.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.PublicKey;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>PublicKey</code> class field
+ * 
+ */
+
+public class PublicKeyTest extends TestCase {
+
+
+    /**
+     * Constructor for PublicKeyTest.
+     * 
+     * @param arg0
+     */
+    public PublicKeyTest(String arg0) {
+        super(arg0);
+    }
+
+    /**
+     * Test for <code>serialVersionUID</code> field
+     */
+    public void testField() {
+        checkPublicKey cPK = new checkPublicKey();
+        assertEquals("Incorrect serialVersionUID", cPK.getSerVerUID(), //PublicKey.serialVersionUID,
+                7187392471159151072L);
+    }
+    
+    public class checkPublicKey implements PublicKey {
+        public String getAlgorithm() {
+            return "PublicKey";
+        }
+        public String getFormat() {
+            return "Format";
+        }
+        public byte[] getEncoded() {
+            return new byte[0];
+        }
+        public long getSerVerUID() {
+            return serialVersionUID;
+        }        
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SecureClassLoader2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SecureClassLoader2Test.java
new file mode 100644
index 0000000..0fb46c9
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SecureClassLoader2Test.java
@@ -0,0 +1,77 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.CodeSource;
+import java.security.PermissionCollection;
+import java.security.ProtectionDomain;
+import java.security.SecureClassLoader;
+import java.security.cert.Certificate;
+import java.util.Enumeration;
+import java.util.jar.JarFile;
+
+public class SecureClassLoader2Test extends junit.framework.TestCase {
+
+    /**
+     * @tests java.security.SecureClassLoader#getPermissions(java.security.CodeSource)
+     */
+    public void test_getPermissionsLjava_security_CodeSource() {
+        class MyClassLoader extends SecureClassLoader {
+            public PermissionCollection getPerms() {
+                return super.getPermissions(new CodeSource(null,
+                        (Certificate[]) null));
+            }
+
+            public Class define(String name, byte[] bytes) {
+                return defineClass(name, bytes, 0, bytes.length,
+                        (ProtectionDomain) null);
+            }
+        }
+
+        MyClassLoader myloader = new MyClassLoader();
+        PermissionCollection pc = myloader.getPerms();
+        Enumeration e1 = pc.elements();
+        int count = 0;
+        while (e1.hasMoreElements()) {
+            e1.nextElement();
+            count++;
+        }
+        assertEquals("expected no permissions", 0, count);
+
+        byte[] bytes = null;
+        try {
+            File file = new File(ClassLoader.getSystemClassLoader()
+                    .getResource("hyts_security.jar").getFile());
+            JarFile jar = new JarFile(file);
+            InputStream in = jar.getInputStream(jar
+                    .getEntry("packA/SecurityTest.class"));
+            bytes = new byte[in.available()];
+            in.read(bytes);
+            in.close();
+        } catch (IOException e) {
+            fail("unexpected IOException : " + e);
+        }
+        Class c = myloader.define("packA.SecurityTest", bytes);
+        ProtectionDomain pd = c.getProtectionDomain();
+        assertNotNull("Expected dynamic policy", pd.getClassLoader());
+        assertNull("Expected null permissions", pd.getPermissions());
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SecureRandom2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SecureRandom2Test.java
new file mode 100644
index 0000000..cace494
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SecureRandom2Test.java
@@ -0,0 +1,298 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.SecureRandomSpi;
+import java.security.Security;
+
+import junit.framework.TestCase;
+
+public class SecureRandom2Test extends TestCase {
+
+    private static final byte[] SEED_BYTES = { (byte) 33, (byte) 15, (byte) -3,
+            (byte) 22, (byte) 77, (byte) -16, (byte) -33, (byte) 56 };
+
+    private static final int SEED_SIZE = 539;
+
+    private static final long SEED_VALUE = 5335486759L;
+
+    public void testGetProvider() {
+        SecureRandom sr1 = new SecureRandom();
+        assertNotNull(sr1.getProvider());
+
+        SecureRandom sr2 = new SecureRandom(SEED_BYTES);
+        assertNotNull(sr2.getProvider());
+
+        MyProvider p = new MyProvider();
+
+        MySecureRandom sr3 = new MySecureRandom(new MySecureRandomSpi(), p);
+        assertEquals(p, sr3.getProvider());
+        try {
+            SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
+            assertNotNull(random.getProvider());
+        } catch (NoSuchAlgorithmException e) {
+            fail("Unexpected NoSuchAlgorithmException");
+        }
+    }
+
+    /**
+     * @tests java.security.SecureRandom#SecureRandom()
+     */
+    public void test_Constructor() {
+        // Test for method java.security.SecureRandom()
+        try {
+            new SecureRandom();
+        } catch (Exception e) {
+            fail("Constructor threw exception : " + e);
+        }
+    }
+
+    /**
+     * @tests java.security.SecureRandom#SecureRandom(byte[])
+     */
+    public void test_Constructor$B() {
+        // Test for method java.security.SecureRandom(byte [])
+        try {
+            new SecureRandom(SEED_BYTES);
+        } catch (Exception e) {
+            fail("Constructor threw exception : " + e);
+        }
+    }
+
+    /**
+     * @tests java.security.SecureRandom#SecureRandom(java.security.SecureRandomSpi,
+     *        java.security.Provider)
+     */
+    public void test_ConstructorLjava_security_SecureRandomSpi_java_security_Provider() {
+        try {
+            new MySecureRandom(null, null);
+        } catch (Exception e) {
+            fail("Constructor threw exception : " + e);
+        }
+
+        try {
+            MyProvider p = new MyProvider();
+            MySecureRandom sr = new MySecureRandom(new MySecureRandomSpi(), p);
+            assertEquals("unknown", sr.getAlgorithm());
+            assertEquals(p, sr.getProvider());
+        } catch (Exception e) {
+            fail("Constructor threw exception : " + e);
+        }
+
+    }
+
+    /**
+     * @tests java.security.SecureRandom#generateSeed(int)
+     */
+    public void test_generateSeedI() {
+        // Test for method byte [] java.security.SecureRandom.generateSeed(int)
+        byte[] seed = new SecureRandom().generateSeed(SEED_SIZE);
+        assertEquals("seed has incorrect size", SEED_SIZE, seed.length);
+    }
+
+    /**
+     * @tests java.security.SecureRandom#getInstance(java.lang.String)
+     */
+    public void test_getInstanceLjava_lang_String() {
+        // Test for method java.security.SecureRandom
+        // java.security.SecureRandom.getInstance(java.lang.String)
+        try {
+            SecureRandom.getInstance("SHA1PRNG");
+        } catch (NoSuchAlgorithmException e) {
+            fail("getInstance did not find a SHA1PRNG algorithm");
+        }
+    }
+
+    /**
+     * @tests java.security.SecureRandom#getInstance(java.lang.String,
+     *        java.lang.String)
+     */
+    public void test_getInstanceLjava_lang_StringLjava_lang_String() {
+        // Test for method java.security.SecureRandom
+        // java.security.SecureRandom.getInstance(java.lang.String,
+        // java.lang.String)
+        try {
+            Provider[] providers = Security
+                    .getProviders("SecureRandom.SHA1PRNG");
+            if (providers != null) {
+                for (int i = 0; i < providers.length; i++) {
+                    SecureRandom
+                            .getInstance("SHA1PRNG", providers[i].getName());
+                }// end for
+            } else {
+                fail("No providers support SHA1PRNG");
+            }
+        } catch (NoSuchAlgorithmException e) {
+            fail("getInstance did not find a SHA1PRNG algorithm");
+        } catch (NoSuchProviderException e) {
+            fail("getInstance did not find the provider for SHA1PRNG");
+        }
+    }
+
+    /**
+     * @tests java.security.SecureRandom#getSeed(int)
+     */
+    public void test_getSeedI() {
+        // Test for method byte [] java.security.SecureRandom.getSeed(int)
+        byte[] seed = SecureRandom.getSeed(SEED_SIZE);
+        assertEquals("seed has incorrect size", SEED_SIZE, seed.length);
+    }
+
+    /**
+     * @tests java.security.SecureRandom#nextBytes(byte[])
+     */
+    public void test_nextBytes$B() {
+        // Test for method void java.security.SecureRandom.nextBytes(byte [])
+        byte[] bytes = new byte[313];
+        try {
+            new SecureRandom().nextBytes(bytes);
+        } catch (Exception e) {
+            fail("next bytes not ok : " + e);
+        }
+    }
+
+    /**
+     * @tests java.security.SecureRandom#setSeed(byte[])
+     */
+    public void test_setSeed$B() {
+        // Test for method void java.security.SecureRandom.setSeed(byte [])
+        try {
+            new SecureRandom().setSeed(SEED_BYTES);
+        } catch (Exception e) {
+            fail("seed generation with bytes failed : " + e);
+        }
+    }
+
+    /**
+     * @tests java.security.SecureRandom#setSeed(long)
+     */
+    public void test_setSeedJ() {
+        // Test for method void java.security.SecureRandom.setSeed(long)
+        try {
+            new SecureRandom().setSeed(SEED_VALUE);
+        } catch (Exception e) {
+            fail("seed generation with long failed : " + e);
+        }
+    }
+
+    /**
+     * @tests java.security.SecureRandom#getAlgorithm()
+     */
+    public void test_getAlgorithm() {
+        // Regression for HARMONY-750
+
+        SecureRandomSpi spi = new SecureRandomSpi() {
+
+            protected void engineSetSeed(byte[] arg) {
+            }
+
+            protected void engineNextBytes(byte[] arg) {
+            }
+
+            protected byte[] engineGenerateSeed(int arg) {
+                return null;
+            }
+        };
+
+        SecureRandom sr = new SecureRandom(spi, null) {
+        };
+
+        assertEquals("unknown", sr.getAlgorithm());
+    }
+
+    // Regression Test for HARMONY-3552.
+    public void test_nextJ() throws Exception {
+        MySecureRandom mySecureRandom = new MySecureRandom(
+                new MySecureRandomSpi(), null);
+        int numBits = 29;
+        int random = mySecureRandom.getNext(numBits);
+        assertEquals(numBits, Integer.bitCount(random));
+
+        numBits = 0;
+        random = mySecureRandom.getNext(numBits);
+        assertEquals(numBits, Integer.bitCount(random));
+
+        numBits = 40;
+        random = mySecureRandom.getNext(numBits);
+        assertEquals(32, Integer.bitCount(random));
+
+        numBits = -1;
+        random = mySecureRandom.getNext(numBits);
+        assertEquals(0, Integer.bitCount(random));
+    }
+
+    class MySecureRandom extends SecureRandom {
+        private static final long serialVersionUID = 1L;
+
+        public MySecureRandom(SecureRandomSpi secureRandomSpi, Provider provider) {
+            super(secureRandomSpi, provider);
+        }
+
+        public int getNext(int numBits) {
+            return super.next(numBits);
+        }
+    }
+
+    class MySecureRandomSpi extends SecureRandomSpi {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        protected byte[] engineGenerateSeed(int arg0) {
+            return null;
+        }
+
+        @Override
+        protected void engineNextBytes(byte[] bytes) {
+            for (int i = 0; i < bytes.length; i++) {
+                bytes[i] = (byte) 0xFF;
+            }
+        }
+
+        @Override
+        protected void engineSetSeed(byte[] arg0) {
+            return;
+        }
+    }
+
+    class MyProvider extends Provider {
+
+        MyProvider() {
+            super("MyProvider", 1.0, "Provider for testing");
+            put("MessageDigest.SHA-1", "SomeClassName");
+            put("MessageDigest.abc", "SomeClassName");
+            put("Alg.Alias.MessageDigest.SHA1", "SHA-1");
+        }
+
+        MyProvider(String name, double version, String info) {
+            super(name, version, info);
+        }
+
+        public void putService(Provider.Service s) {
+            super.putService(s);
+        }
+
+        public void removeService(Provider.Service s) {
+            super.removeService(s);
+        }
+
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/Security2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/Security2Test.java
new file mode 100644
index 0000000..954ff6e
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/Security2Test.java
@@ -0,0 +1,338 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.InvalidParameterException;
+import java.security.Provider;
+import java.security.Security;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import tests.support.Support_ProviderTrust;
+import tests.support.Support_TestProvider;
+
+
+public class Security2Test extends junit.framework.TestCase {
+
+    /**
+     * @tests java.security.Security#getProviders(java.lang.String)
+     */
+    public void test_getProvidersLjava_lang_String() {
+        // Test for method void
+        // java.security.Security.getProviders(java.lang.String)
+
+        Hashtable<String, Integer> allSupported = new Hashtable<String, Integer>();
+        Provider[] allProviders = Security.getProviders();
+
+        // Add all non-alias entries to allSupported
+        for (int i = 0; i < allProviders.length; i++) {
+            Provider provider = allProviders[i];
+            Iterator it = provider.entrySet().iterator();
+            while (it.hasNext()) {
+                Map.Entry entry = (Map.Entry) it.next();
+                String key = (String) entry.getKey();
+                // No aliases and no provider data
+                if (!isAlias(key) && !isProviderData(key)) {
+                    addOrIncrementTable(allSupported, key);
+                }
+            }// end while more entries
+        }// end for all providers
+
+        // Now walk through aliases. If an alias has actually been added
+        // to the allSupported table then increment the count of the
+        // entry that is being aliased.
+        for (int i = 0; i < allProviders.length; i++) {
+            Provider provider = allProviders[i];
+            Iterator it = provider.entrySet().iterator();
+            while (it.hasNext()) {
+                Map.Entry entry = (Map.Entry) it.next();
+                String key = (String) entry.getKey();
+                if (isAlias(key)) {
+                    String aliasVal = key.substring("ALG.ALIAS.".length());
+                    String aliasKey = aliasVal.substring(0, aliasVal
+                            .indexOf(".") + 1)
+                            + entry.getValue();
+                    // Skip over nonsense alias declarations where alias and
+                    // aliased are identical. Such entries can occur.
+                    if (!aliasVal.equals(aliasKey)) {
+                        // Has a real entry been added for aliasValue ?
+                        if (allSupported.containsKey(aliasVal)) {
+                            // Add 1 to the provider count of the thing being
+                            // aliased
+                            addOrIncrementTable(allSupported, aliasKey);
+                        }
+                    }
+                }
+            }// end while more entries
+        }// end for all providers
+
+        Provider provTest[] = null;
+        Iterator it = allSupported.keySet().iterator();
+        while (it.hasNext()) {
+            String filterString = (String) it.next();
+            try {
+                provTest = Security.getProviders(filterString);
+                int expected = ((Integer) allSupported.get(filterString))
+                        .intValue();
+                assertEquals(
+                        "Unexpected number of providers returned for filter "
+                                + filterString, expected, provTest.length);
+            } catch (InvalidParameterException e) {
+                // NO OP
+            }
+        }// end while
+
+        // exception
+        try {
+            provTest = Security.getProviders("Signature.SHA1withDSA :512");
+            fail("InvalidParameterException should be thrown <Signature.SHA1withDSA :512>");
+        } catch (InvalidParameterException e) {
+            // Expected
+        }
+    }
+
+    /**
+     * @param key
+     * @return
+     */
+    private boolean isProviderData(String key) {
+        return key.toUpperCase().startsWith("PROVIDER.");
+    }
+
+    /**
+     * @param key
+     * @return
+     */
+    private boolean isAlias(String key) {
+        return key.toUpperCase().startsWith("ALG.ALIAS.");
+    }
+
+    /**
+     * @param table
+     * @param key
+     */
+    private void addOrIncrementTable(Hashtable<String, Integer> table, String key) {
+        if (table.containsKey(key)) {
+            Integer before = (Integer) table.get(key);
+            table.put(key, new Integer(before.intValue() + 1));
+        } else {
+            table.put(key, new Integer(1));
+        }
+    }
+
+    /**
+     * @param filterMap
+     * @return
+     */
+    private int getProvidersCount(Map filterMap) {
+        int result = 0;
+        Provider[] allProviders = Security.getProviders();
+
+        // for each provider
+        for (int i = 0; i < allProviders.length; i++) {
+            Provider provider = allProviders[i];
+            Set allProviderKeys = provider.keySet();
+            boolean noMatchFoundForFilterEntry = false;
+
+            // for each filter item
+            Set allFilterKeys = filterMap.keySet();
+            Iterator fkIter = allFilterKeys.iterator();
+            while (fkIter.hasNext()) {
+                String filterString = ((String) fkIter.next()).trim();
+
+                // Remove any "=" characters that may be on the end of the
+                // map keys (no, I don't know why they might be there either
+                // but I have seen them)
+                if (filterString.endsWith("=")) {
+                    filterString = filterString.substring(0, filterString
+                            .length() - 1);
+                }
+
+                if (filterString != null) {
+                    if (filterString.indexOf(" ") == -1) {
+                        // Is this filter string in the keys of the
+                        // current provider ?
+                        if (!allProviderKeys.contains(filterString)) {
+                            // Check that the key is not contained as an
+                            // alias.
+                            if (!allProviderKeys.contains("Alg.Alias."
+                                    + filterString)) {
+                                noMatchFoundForFilterEntry = true;
+                                break; // out of while loop
+                            }
+                        }
+                    } else {
+                        // handle filter strings with attribute names
+                        if (allProviderKeys.contains(filterString)) {
+                            // Does the corresponding values match ?
+                            String filterVal = (String) filterMap
+                                    .get(filterString);
+                            String providerVal = (String) provider
+                                    .get(filterString);
+                            if (providerVal == null
+                                    || !providerVal.equals(filterVal)) {
+                                noMatchFoundForFilterEntry = true;
+                                break; // out of while loop
+                            }
+                        }// end if filter string with named attribute is
+                        // found
+                    }// end else
+                }// end if non-null key
+            }// end while there are more filter strings for current map
+
+            if (!noMatchFoundForFilterEntry) {
+                // Current provider is a match for the filterMap
+                result++;
+            }
+        }// end for each provider
+
+        return result;
+    }
+
+    /**
+     * @tests java.security.Security#getProviders(java.util.Map)
+     */
+    public void test_getProvidersLjava_util_Map() {
+        // Test for method void
+        // java.security.Security.getProviders(java.util.Map)
+
+        Map<String, String> filter = new Hashtable<String, String>();
+        filter.put("KeyStore.BKS", "");
+        filter.put("Signature.SHA1withDSA", "");
+        Provider provTest[] = Security.getProviders(filter);
+        if (provTest == null) {
+            assertEquals("Filter : <KeyStore.BKS>,<Signature.SHA1withDSA>",
+                    0, getProvidersCount(filter));
+        } else {
+            assertEquals("Filter : <KeyStore.BKS>,<Signature.SHA1withDSA>",
+                    getProvidersCount(filter), provTest.length);
+        }
+
+        filter = new Hashtable<String, String>();
+        filter.put("MessageDigest.MD2", "");
+        filter.put("CertificateFactory.X.509", "");
+        filter.put("KeyFactory.RSA", "");
+        provTest = Security.getProviders(filter);
+        if (provTest == null) {
+            assertEquals("Filter : <MessageDigest.MD2>,<CertificateFactory.X.509>,<KeyFactory.RSA>",
+                    0, getProvidersCount(filter));
+        } else {
+            assertEquals(
+                    "Filter : <MessageDigest.MD2>,<CertificateFactory.X.509>,<KeyFactory.RSA>",
+                    getProvidersCount(filter), provTest.length);
+        }
+
+        filter = new Hashtable<String, String>();
+        filter.put("MessageDigest.SHA", "");
+        filter.put("CertificateFactory.X.509", "");
+        provTest = Security.getProviders(filter);
+        if (provTest == null) {
+            assertEquals("Filter : <MessageDigest.SHA><CertificateFactory.X.509>",
+                    0, getProvidersCount(filter));
+        } else {
+            assertEquals(
+                    "Filter : <MessageDigest.SHA><CertificateFactory.X.509>",
+                    getProvidersCount(filter), provTest.length);
+        }
+
+        filter = new Hashtable<String, String>();
+        filter.put("CertificateFactory.X509", "");
+        provTest = Security.getProviders(filter);
+        if (provTest == null) {
+            assertEquals("Filter : <CertificateFactory.X509>",
+                    0, getProvidersCount(filter));
+        } else {
+            assertEquals("Filter : <CertificateFactory.X509>",
+                    getProvidersCount(filter), provTest.length);
+        }
+
+        filter = new Hashtable<String, String>();
+        filter.put("Provider.id name", "DRLCertFactory");
+        provTest = Security.getProviders(filter);
+        assertNull("Filter : <Provider.id name, DRLCertFactory >",
+                provTest);
+
+        // exception - no attribute name after the service.algorithm yet we
+        // still supply an expected value. This is not valid.
+        try {
+            filter = new Hashtable<String, String>();
+            filter.put("Signature.SHA1withDSA", "512");
+            provTest = Security.getProviders(filter);
+            fail("InvalidParameterException should be thrown <Signature.SHA1withDSA><512>");
+        } catch (InvalidParameterException e) {
+            // Expected
+        }
+
+        // exception - space character in the service.algorithm pair. Not valid.
+        try {
+            filter = new Hashtable<String, String>();
+            filter.put("Signature. KeySize", "512");
+            provTest = Security.getProviders(filter);
+            fail("InvalidParameterException should be thrown <Signature. KeySize><512>");
+        } catch (InvalidParameterException e) {
+            // Expected
+        }
+    }
+
+    /**
+     * @tests java.security.Security#removeProvider(java.lang.String)
+     */
+    public void test_removeProviderLjava_lang_String() {
+        // Test for method void
+        // java.security.Security.removeProvider(java.lang.String)
+        Provider test = new Support_TestProvider();
+        Provider entrust = new Support_ProviderTrust();
+        try {
+            // Make sure provider not already loaded. Should do nothing
+            // if not already loaded.
+            Security.removeProvider(test.getName());
+
+            // Now add it
+            int addResult = Security.addProvider(test);
+            assertTrue("Failed to add provider", addResult != -1);
+
+            Security.removeProvider(test.getName());
+            assertNull(
+                    "the provider TestProvider is found after it was removed",
+                    Security.getProvider(test.getName()));
+
+            // Make sure entrust provider not already loaded. Should do nothing
+            // if not already loaded.
+            Security.removeProvider(entrust.getName());
+
+            // Now add entrust
+            addResult = Security.addProvider(entrust);
+            assertTrue("Failed to add provider", addResult != -1);
+
+            Security.removeProvider(entrust.getName());
+            Provider provTest[] = Security.getProviders();
+            for (int i = 0; i < provTest.length; i++) {
+                assertTrue(
+                        "the provider entrust is found after it was removed",
+                        provTest[i].getName() != entrust.getName());
+            }
+        } finally {
+            // Tidy up - the following calls do nothing if the providers were
+            // already removed above.
+            Security.removeProvider(test.getName());
+            Security.removeProvider(entrust.getName());
+        }
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SecurityPermission2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SecurityPermission2Test.java
new file mode 100644
index 0000000..defc4dc
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SecurityPermission2Test.java
@@ -0,0 +1,47 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.SecurityPermission;
+
+public class SecurityPermission2Test extends junit.framework.TestCase {
+
+    /**
+     * @tests java.security.SecurityPermission#SecurityPermission(java.lang.String)
+     */
+    public void test_ConstructorLjava_lang_String() {
+        // Test for method java.security.SecurityPermission(java.lang.String)
+        assertEquals("create securityPermission constructor(string) failed",
+                "SecurityPermission(string)", new SecurityPermission("SecurityPermission(string)").getName()
+                        );
+
+    }
+
+    /**
+     * @tests java.security.SecurityPermission#SecurityPermission(java.lang.String,
+     *        java.lang.String)
+     */
+    public void test_ConstructorLjava_lang_StringLjava_lang_String() {
+        // Test for method java.security.SecurityPermission(java.lang.String,
+        // java.lang.String)
+        SecurityPermission sp = new SecurityPermission("security.file", "write");
+        assertEquals("creat securityPermission constructor(string,string) failed",
+                "security.file", sp.getName());
+
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SecurityPermissionTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SecurityPermissionTest.java
new file mode 100644
index 0000000..2c9b2bf
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SecurityPermissionTest.java
@@ -0,0 +1,85 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.SecurityPermission;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>SecurityPermission</code>
+ * 
+ */
+public class SecurityPermissionTest extends TestCase {
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(SecurityPermissionTest.class);
+    }
+
+    /**
+     * Constructor for SecurityPermissionTest.
+     * @param arg0
+     */
+    public SecurityPermissionTest(String arg0) {
+        super(arg0);
+    }
+    
+    /**
+     * Check all constructors: an object is created with the specified valid name. 
+     * If name equal null then NPE should be thrown. 
+     * If  name is empty then IAE should be thrown. 
+     * Action is ignored.
+     */
+    public void testCtor()
+    {
+        String name = "basic123*$%#";
+        SecurityPermission test = new SecurityPermission(name);
+        assertEquals(name, test.getName());
+        assertEquals("", test.getActions());
+        test = new SecurityPermission(name, "#$!#12435");
+        assertEquals(name, test.getName());
+        assertEquals("", test.getActions());
+        try{
+            new SecurityPermission(null);
+            fail("NPE is not thrown");
+        }
+        catch (NullPointerException ok){}
+        
+        try{
+            new SecurityPermission(null, "ds235");
+            fail("NPE is not thrown");
+        }
+        catch (NullPointerException ok){}
+        
+        try{
+            new SecurityPermission("");
+            fail("IAE is not thrown");
+        }
+        catch (IllegalArgumentException ok){}
+        try{
+            new SecurityPermission("", "ertre 3454");
+            fail("IAE is not thrown");
+        }
+        catch (IllegalArgumentException ok){} 
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SecurityTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SecurityTest.java
new file mode 100644
index 0000000..c56b9ec
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SecurityTest.java
@@ -0,0 +1,430 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Boris V. Kuznetsov
+ * @version $Revision$
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.InvalidParameterException;
+import java.security.KeyFactory;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.Security;
+import java.security.Signature;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.harmony.security.tests.support.TestKeyPair;
+
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>Security</code> constructor and methods
+ */
+public class SecurityTest extends TestCase {
+
+    public final void testMixed() {
+
+        TestKeyPair tkp = null;
+        try {
+            tkp = new TestKeyPair("DSA");
+        } catch (NoSuchAlgorithmException e1) {
+            e1.printStackTrace();
+            return;
+        }
+
+        try {
+            MessageDigest.getInstance("SHA-1");
+            KeyFactory.getInstance("DSA");
+            Signature ss = Signature.getInstance("DSA");
+            ss.initSign(tkp.getPrivate());
+            Signature.getInstance("aaaaaaaaaaaa");
+        } catch (Exception e) {
+            // ignore
+        }
+
+    }
+
+    /**
+     * @tests java.security.Security#insertProviderAt(Provider, int)
+     */
+    public final void test_insertProviderAtLjava_security_ProviderLI() {
+
+        try {
+            Security.insertProviderAt(null, 1);
+            fail("No expected NullPointerException");
+        } catch (NullPointerException e) {
+        }
+
+        Provider p = new MyProvider();
+        int initNum = Security.getProviders().length; // initial number of
+        // providers
+        Provider initialSecondProviderName = Security.getProviders()[1];
+
+        try {
+
+            // Insert at position -1, the provider is inserted at the end
+            assertEquals(initNum + 1, Security.insertProviderAt(p, -1));
+            assertSame(p, Security.getProviders()[initNum]);
+
+            // A provider cannot be added if it is already installed
+            assertEquals(-1, Security.insertProviderAt(p, 1));
+
+            Security.removeProvider(p.getName());
+
+            // insert at the end
+            assertEquals(initNum + 1, Security.insertProviderAt(p,
+                    initNum + 100));
+            assertSame(p, Security.getProviders()[initNum]);
+
+            Security.removeProvider(p.getName());
+
+            // insert at the first position
+            assertEquals(1, Security.insertProviderAt(p, 1));
+            assertSame(p, Security.getProviders()[0]);
+            assertSame(initialSecondProviderName, // provider shifted down
+                    Security.getProviders()[2]);
+        } finally { // clean up
+            Security.removeProvider(p.getName());
+        }
+    }
+
+    /**
+     * @tests java.security.Security#addProvider(Provider)
+     */
+    public final void test_addProviderLjava_security_Provider() {
+
+        try {
+            Security.addProvider(null);
+            fail("No expected NullPointerException");
+        } catch (NullPointerException e) {
+        }
+
+        Provider p = new MyProvider();
+        int initNum = Security.getProviders().length; // initial number of
+        // providers
+
+        try {
+            // add
+            assertEquals(initNum + 1, Security.addProvider(p));
+            assertSame(p, Security.getProviders()[initNum]);
+
+            // A provider cannot be added if it is already installed
+            assertEquals(-1, Security.addProvider(p));
+        } finally { // clean up
+            Security.removeProvider(p.getName());
+        }
+    }
+
+    /**
+     * @tests java.security.Security#getAlgorithmProperty(String algName,
+     *        String propName)
+     */
+    @SuppressWarnings("deprecation")
+    public final void testGetAlgorithmPropertyLjava_lang_String_java_lang_String() {
+        String propName = null;
+        
+        Provider provider = new MyProvider();
+        Map<String, String> m = new HashMap<String, String>();
+        m.clear();
+        m.put("Alg.propName.algName", "value");
+        provider.putAll(m);
+        
+        Security.addProvider(provider);
+        
+        assertNotNull(Security.getAlgorithmProperty("algName", "propName"));
+
+        assertNull(Security.getAlgorithmProperty("DSA", propName));
+        assertNull(Security.getAlgorithmProperty("DSA", "propName"));
+        Security.removeProvider(provider.getName());
+    }
+
+    /**
+     * @tests java.security.Security#getAlgorithms(String serviceName)
+     */
+    public final void testGetAlgorithmsLjava_lang_String() {
+        String[] servicesNames = { "Signature", "MessageDigest", "Cipher",
+                "Mac", "KeyStore" };
+
+        String[][] algorithms = {
+                { "SHA256WITHRSA", "NONEWITHDSA", "SHA384WITHRSA",
+                        "MD2WITHRSA", "MD5ANDSHA1WITHRSA", "SHA512WITHRSA",
+                        "SHA1WITHRSA", "SHA1WITHDSA", "MD5WITHRSA" },
+                { "SHA-512", "MD2", "SHA", "SHA-256", "MD5", "SHA-384" },
+                { "ARCFOUR", "PBEWITHSHA1ANDDESEDE", "DESEDEWRAP",
+                        "PBEWITHMD5ANDTRIPLEDES", "DESEDE", "RSA", "AESWRAP",
+                        "AES", "PBEWITHMD5ANDDES", "BLOWFISH", "DES", "RC2",
+                        "PBEWITHSHA1ANDRC2_40" },
+                { "HMACSHA512", "HMACSHA1", "HMACMD5", "HMACPBESHA1",
+                        "HMACSHA256", "HMACSHA384" },
+                { "PKCS12", "CASEEXACTJKS", "JKS", "JCEKS" } };
+
+        for (int i = 0; i < servicesNames.length; i++) {
+            Set<String> algs = Security.getAlgorithms(servicesNames[i]);
+            Object[] actualAlgs = algs.toArray();
+            assertTrue(Arrays.equals(actualAlgs, algorithms[i]));
+        }
+    }
+
+    public final void testRemoveProvider() {
+        Provider[] providers;
+        Provider[] providers1;
+
+        providers = Security.getProviders();
+
+        try {
+            for (int i = 0; i < providers.length; i++) {
+                Security.removeProvider(providers[i].getName());
+            }
+            assertEquals("Providers not removed", 0,
+                    Security.getProviders().length);
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally { // restore providers
+            for (int i = 0; i < providers.length; i++) {
+                Security.addProvider(providers[i]);
+            }
+            providers1 = Security.getProviders();
+            for (int i = 0; i < providers1.length; i++) {
+                assertEquals("Providers not restored correctly", providers[i],
+                        providers1[i]);
+            }
+        }
+    }
+
+    /**
+     * @tests java.security.Security#getProvider(String)
+     */
+    public final void test_getProviderLjava_lang_String() {
+
+        // Returns null if no provider with the specified name is installed
+        assertNull(Security.getProvider("SOMEINCORRECTPROVIDERNAME"));
+
+        // Returns null if name is null
+        assertNull(Security.getProvider(null));
+
+        // test for existing providers
+        Provider[] providers = Security.getProviders();
+        assertTrue("getProviders returned zero length array",
+                providers.length > 0);
+        for (Provider p : providers) {
+            String providerName = p.getName();
+            assertSame(p, Security.getProvider(providerName));
+        }
+
+        // test for newly installed provider
+        Provider p = new MyProvider();
+        try {
+            Security.addProvider(p);
+
+            assertSame(p, Security.getProvider(p.getName()));
+        } finally { // clean up
+            Security.removeProvider(p.getName());
+        }
+    }
+
+    /**
+     * @tests java.security.Security#getProviders(String)
+     */
+    public void test_getProvidersLjava_lang_String() {
+
+        try {
+            Security.getProviders("");
+            fail("No expected InvalidParameterException");
+        } catch (InvalidParameterException e) {
+        }
+
+        try {
+            Security.getProviders((String) null);
+            fail("No expected NullPointerException");
+        } catch (NullPointerException e) {
+        }
+
+        Provider p = new MyProvider();
+        try {
+            Security.addProvider(p);
+
+            String filter = "MyService.MyAlgorithm";
+            assertTrue(filter, Arrays.equals(new Provider[] { p }, Security
+                    .getProviders(filter)));
+
+            filter = "MyService.MyAlgorithm KeySize:512";
+            assertTrue(filter, Arrays.equals(new Provider[] { p }, Security
+                    .getProviders(filter)));
+
+            filter = "MyService.MyAlgorithm KeySize:1025";
+            assertNull(filter, Security.getProviders(filter));
+
+            // attribute name and value are case insensitive
+            filter = "MyService.MyAlgorithm imPLementedIn:softWARE";
+            assertTrue(filter, Arrays.equals(new Provider[] { p }, Security
+                    .getProviders(filter)));
+            filter = "MyService.MyAlgorithm ATTribute:attributeVALUE";
+            assertTrue(filter, Arrays.equals(new Provider[] { p }, Security
+                    .getProviders(filter)));
+
+            // Regression for HARMONY-2761
+            filter = "MyService.NoKeySize KeySize:512";
+            assertNull(filter, Security.getProviders(filter));
+
+            filter = "MyService.NoImplementedIn ImplementedIn:Software";
+            assertNull(filter, Security.getProviders(filter));
+
+            filter = "ABCService.NoAttribute Attribute:ABC";
+            assertNull(filter, Security.getProviders(filter));
+        } finally { // clean up
+            Security.removeProvider(p.getName());
+        }
+    }
+
+    /**
+     * @tests java.security.Security#getProviders(java.util.Map)
+     */
+    public void test_getProvidersLjava_util_Map() {
+
+        Map<String, String> m = new HashMap<String, String>();
+        Security.getProviders(m);
+
+        assertNull("Not null result on empty map", Security.getProviders(m));
+
+        try {
+            Security.getProviders((Map<String, String>) null);
+            fail("No expected NullPointerException");
+        } catch (NullPointerException e) {
+        }
+
+        m.put("AAA.BBB.CCC", "aaaa"); // key has dot instead of space
+        try {
+            Security.getProviders(m);
+            fail("No expected InvalidParameterException");
+        } catch (InvalidParameterException e) {
+        }
+
+        Provider p = new MyProvider();
+        try {
+            Security.addProvider(p);
+
+            m.clear();
+            m.put("MyService.MyAlgorithm", "");
+            m.put("MessageDigest.SHA-1", "");
+            assertTrue("MyService.MyAlgorithm", Arrays.equals(
+                    new Provider[] { p }, Security.getProviders(m)));
+
+            m.clear();
+            m.put("MyService.MyAlgorithm KeySize", "512");
+            m.put("MessageDigest.SHA-1", "");
+            assertTrue("MyService.MyAlgorithm KeySize:512", Arrays.equals(
+                    new Provider[] { p }, Security.getProviders(m)));
+
+            m.clear();
+            m.put("MyService.MyAlgorithm KeySize", "1025");
+            m.put("MessageDigest.SHA-1", "");
+            assertNull("MyService.MyAlgorithm KeySize:1025", Security
+                    .getProviders(m));
+
+            // attribute name and value are case insensitive
+            m.clear();
+            m.put("MyService.MyAlgorithm imPLementedIn", "softWARE");
+            assertTrue(Arrays.equals(new Provider[] { p }, Security
+                    .getProviders(m)));
+            m.clear();
+            m.put("MyService.MyAlgorithm ATTribute", "attributeVALUE");
+            assertTrue(Arrays.equals(new Provider[] { p }, Security
+                    .getProviders(m)));
+
+            // Regression for HARMONY-2761
+            m.clear();
+            m.put("MyService.NoKeySize KeySize", "512");
+            assertNull("No KeySize attribute", Security.getProviders(m));
+
+            m.clear();
+            m.put("MyService.NoImplementedIn ImplementedIn", "Software");
+            assertNull("No ImplementedIn attribute", Security.getProviders(m));
+
+            m.clear();
+            m.put("ABCService.NoAttribute Attribute", "ABC");
+            assertNull(Security.getProviders(m));
+        } finally { // clean up
+            Security.removeProvider(p.getName());
+        }
+    }
+
+    /**
+     * @tests java.security.Security#getProperty(String)
+     */
+    public void test_getPropertyLjava_lang_String() {
+
+        try {
+            Security.getProperty(null);
+            fail("No expected NullPointerException.");
+        } catch (NullPointerException e) {
+        }
+    }
+
+    /**
+     * @tests java.security.Security#setProperty(String,String)
+     */
+    public void test_setPropertyLjava_lang_StringLjava_lang_String() {
+
+        try {
+            Security.setProperty(null, "");
+            fail("No expected NullPointerException.");
+        } catch (NullPointerException e) {
+        }
+
+        try {
+            Security.setProperty("", null);
+            fail("No expected NullPointerException.");
+        } catch (NullPointerException e) {
+        }
+
+        Security.setProperty("", "");
+        assertEquals("Empty property", "", Security.getProperty(""));
+
+        Security.setProperty("My Test Property", "My property value");
+        assertEquals("My property value", Security
+                .getProperty("My Test Property"));
+    }
+
+    @SuppressWarnings("serial")
+    class MyProvider extends Provider {
+        MyProvider() {
+            super("MyProvider", 1.0, "Provider for testing");
+            put("MessageDigest.SHA-1", "SomeClassName");
+            put("MyService.MyAlgorithm", "SomeClassName");
+            put("MyService.MyAlgorithm KeySize", "1024");
+            put("MyService.MyAlgorithm ImplementedIn", "Software");
+            put("MyService.MyAlgorithm Attribute", "AttributeValue");
+
+            // service has no KeySize attribute
+            put("MyService.NoKeySize", "SomeClassName");
+
+            // service has no ImplementedIn attribute
+            put("MyService.NoImplementedIn", "SomeClassName");
+
+            // service has no 'Attribute' attribute
+            put("ABCService.NoAttribute", "SomeClassName");
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/Signature2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/Signature2Test.java
new file mode 100644
index 0000000..3887257
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/Signature2Test.java
@@ -0,0 +1,403 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.security.InvalidParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.Provider;
+import java.security.Security;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.spec.DSAParameterSpec;
+import java.util.HashSet;
+import java.util.Set;
+
+
+public class Signature2Test extends junit.framework.TestCase {
+
+    private static final String MESSAGE = "abc";
+
+    static KeyPair keys;
+    static {
+        try {
+            KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
+            keyGen.initialize(1024);
+            keys = keyGen.generateKeyPair();
+        } catch (Exception e) {
+            fail(e.toString());
+        }
+    }
+
+    /**
+     * @tests java.security.Signature#clone()
+     */
+    public void test_clone() throws Exception {
+        Signature s = Signature.getInstance("DSA");
+        try {
+            s.clone();
+            fail("A Signature may not be cloneable");
+        } catch (CloneNotSupportedException e) {
+            // Expected - a Signature may not be cloneable
+        }
+    }
+
+    /**
+     * @tests java.security.Signature#getAlgorithm()
+     */
+    public void test_getAlgorithm() throws Exception {
+        String alg = Signature.getInstance("DSA").getAlgorithm();
+        assertTrue("getAlgorithm did not get DSA (" + alg + ")", alg
+                .indexOf("DSA") != -1);
+    }
+
+    /**
+     * @tests java.security.Signature#getInstance(java.lang.String)
+     */
+    public void test_getInstanceLjava_lang_String() throws Exception {
+        Signature.getInstance("DSA");
+    }
+
+    /**
+     * @tests java.security.Signature#getInstance(java.lang.String,
+     *        java.security.Provider)
+     */
+    public void test_getInstanceLjava_lang_StringLjava_lang_String_java_security_Provider()
+            throws Exception {
+        Provider[] providers = Security.getProviders("Signature.DSA");
+
+        for (int i = 0; i < providers.length; i++) {
+            Signature signature = Signature.getInstance("DSA", providers[i]);
+            assertEquals("DSA", signature.getAlgorithm());
+            assertEquals(providers[i], signature.getProvider());
+        }
+
+        try {
+            Signature.getInstance((String) null, (Provider) null);
+            fail("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // expected
+        }
+
+        try {
+            Signature.getInstance("DSA", (Provider) null);
+            fail("IllegalArgumentException expected");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+
+        try {
+            Signature.getInstance((String) null, providers[0]);
+            fail("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    /**
+     * @tests java.security.Signature#getInstance(java.lang.String,
+     *        java.lang.String)
+     */
+    public void test_getInstanceLjava_lang_StringLjava_lang_String()
+            throws Exception {
+        Provider[] providers = Security.getProviders("Signature.DSA");
+
+        for (int i = 0; i < providers.length; i++) {
+            Signature.getInstance("DSA", providers[i].getName());
+        }// end for
+    }
+
+    /**
+     * @tests java.security.Signature#getParameters()
+     */
+    public void test_getParameters() throws Exception {
+        Signature sig = Signature.getInstance("DSA");
+        try {
+            sig.getParameters();
+        } catch (UnsupportedOperationException e) {
+            // Could be that the operation is not supported
+        }
+    }
+
+    /**
+     * @tests java.security.Signature#getParameter(java.lang.String)
+     */
+    @SuppressWarnings("deprecation")
+    public void test_getParameterLjava_lang_String() throws Exception {
+        Signature sig = Signature.getInstance("DSA");
+
+        try {
+            sig.getParameter("r");
+            sig.getParameter("s");
+        } catch (UnsupportedOperationException e) {
+        }
+    }
+
+    /**
+     * @tests java.security.Signature#getProvider()
+     */
+    public void test_getProvider() throws Exception {
+        Provider p = Signature.getInstance("DSA").getProvider();
+        assertNotNull("provider is null", p);
+    }
+
+    /**
+     * @tests java.security.Signature#initSign(java.security.PrivateKey)
+     */
+    public void test_initSignLjava_security_PrivateKey() throws Exception {
+        Signature.getInstance("DSA").initSign(keys.getPrivate());
+    }
+
+    /**
+     * @tests java.security.Signature#initVerify(java.security.PublicKey)
+     */
+    public void test_initVerifyLjava_security_PublicKey() throws Exception {
+        Signature.getInstance("DSA").initVerify(keys.getPublic());
+    }
+
+    /**
+     * @tests java.security.Signature#initVerify(java.security.cert.Certificate)
+     */
+    public void test_initVerifyLjava_security_Certificate() throws Exception {
+        Provider p = new MyProvider();
+        p.put("DSA", "tests.java.security.support.cert.MyCertificate$1");
+
+        Security.addProvider(new MyProvider());
+
+        Provider[] pp = Security.getProviders();
+        if (pp == null) {
+            return;
+        }
+
+        try {
+            Signature.getInstance("DSA").initVerify((Certificate) null);
+            fail("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // fail
+        }
+
+    }
+
+    /**
+     * @tests java.security.Signature#setParameter(java.lang.String,
+     *        java.lang.Object)
+     */
+    @SuppressWarnings("deprecation")
+    public void test_setParameterLjava_lang_StringLjava_lang_Object()
+            throws Exception {
+        Signature sig = Signature.getInstance("DSA");
+
+        try {
+            sig.setParameter("r", BigInteger.ONE);
+            sig.setParameter("s", BigInteger.ONE);
+        } catch (InvalidParameterException e) {
+            // Could be that it's an invalid param for the found algorithm
+        } catch (UnsupportedOperationException e) {
+            // Could be that the operation is not supported
+        }
+    }
+
+    /**
+     * @tests java.security.Signature#setParameter(java.security.spec.AlgorithmParameterSpec)
+     */
+    public void test_setParameterLjava_security_spec_AlgorithmParameterSpec()
+            throws Exception {
+        Signature sig = Signature.getInstance("DSA");
+
+        try {
+            DSAParameterSpec spec = new DSAParameterSpec(BigInteger.ONE,
+                    BigInteger.ONE, BigInteger.ONE);
+            sig.setParameter(spec);
+        } catch (InvalidParameterException e) {
+            // Could be that it's an invalid param for the found algorithm
+        } catch (UnsupportedOperationException e) {
+            // Could be that the operation is not supported
+        }
+    }
+
+    /**
+     * @tests java.security.Signature#sign()
+     */
+    public void test_sign() throws Exception {
+        Signature sig = Signature.getInstance("DSA");
+        sig.initSign(keys.getPrivate());
+        sig.update(MESSAGE.getBytes());
+        sig.sign();
+    }
+
+    /**
+     * @tests java.security.Signature#toString()
+     */
+    public void test_toString() throws Exception {
+        String str = Signature.getInstance("DSA").toString();
+        assertNotNull("toString is null", str);
+    }
+
+    /**
+     * @tests java.security.Signature#update(byte[])
+     */
+    public void test_update$B() throws Exception {
+        Signature sig = Signature.getInstance("DSA");
+        sig.initSign(keys.getPrivate());
+
+        byte[] bytes = MESSAGE.getBytes();
+        sig.update(bytes);
+    }
+
+    /**
+     * @tests java.security.Signature#update(byte[], int, int)
+     */
+    public void test_update$BII() throws Exception {
+        Signature sig = Signature.getInstance("DSA");
+        sig.initSign(keys.getPrivate());
+
+        byte[] bytes = MESSAGE.getBytes();
+        sig.update(bytes, 0, bytes.length);
+    }
+
+    /**
+     * @tests java.security.Signature#update(byte)
+     */
+    public void test_updateB() throws Exception {
+        Signature sig = Signature.getInstance("DSA");
+        sig.initSign(keys.getPrivate());
+
+        sig.update(MESSAGE.getBytes()[0]);
+    }
+
+    /**
+     * @tests java.security.Signature#update(ByteBuffer data)
+     */
+    public void test_updateLjava_nio_ByteBuffer() throws Exception {
+        Signature sig = Signature.getInstance("DSA");
+        ByteBuffer buffer = ByteBuffer.allocate(10);
+
+        try {
+            sig.update(buffer);
+            fail("SignatureException expected");
+        } catch (SignatureException e) {
+            // expected
+        }
+        try {
+            sig.initSign(keys.getPrivate());
+            sig.update(buffer);
+        } catch (Exception e) {
+            fail("Unexpected exception " + e.getMessage());
+        }
+
+    }
+
+    /**
+     * @tests java.security.Signature#verify(byte[])
+     */
+    public void test_verify$B() throws Exception {
+        Signature sig = Signature.getInstance("DSA");
+        sig.initSign(keys.getPrivate());
+        sig.update(MESSAGE.getBytes());
+        byte[] signature = sig.sign();
+
+        sig.initVerify(keys.getPublic());
+        sig.update(MESSAGE.getBytes());
+        assertTrue("Sign/Verify does not pass", sig.verify(signature));
+    }
+
+    /**
+     * @tests java.security.Signature#verify(byte[], int, int)
+     */
+    public void test_verify$BII() throws Exception {
+        Signature sig = Signature.getInstance("DSA");
+        sig.initSign(keys.getPrivate());
+        sig.update(MESSAGE.getBytes());
+        byte[] signature = sig.sign();
+
+        sig.initVerify(keys.getPublic());
+        sig.update(MESSAGE.getBytes());
+        assertTrue("Sign/Verify does not pass", sig.verify(signature, 0,
+                signature.length));
+
+        try {
+            sig.verify(null, 0, signature.length);
+            fail("IllegalArgumentException expected");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+
+        try {
+            sig.verify(signature, -5, signature.length);
+            fail("IllegalArgumentException expected");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+
+        try {
+            sig.verify(signature, signature.length, 0);
+            fail("SignatureException expected");
+        } catch (SignatureException e) {
+            // expected
+        }
+
+        try {
+            sig.verify(signature, 0, signature.length * 2);
+            fail("IllegalArgumentException expected");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    class MyProvider extends Provider {
+        private Set<Provider.Service> services = null;
+
+        MyProvider() {
+            super("MyProvider", 1.0, "Provider for testing");
+            put("MessageDigest.SHA-1", "SomeClassName");
+            put("MessageDigest.abc", "SomeClassName");
+            put("Alg.Alias.MessageDigest.SHA1", "SHA-1");
+            if (services != null) {
+                services.clear();
+            } else {
+                services = new HashSet<Service>();
+            }
+        }
+
+        MyProvider(String name, double version, String info) {
+            super(name, version, info);
+            if (services != null) {
+                services.clear();
+            } else {
+                services = new HashSet<Service>();
+            }
+        }
+
+        public void putService(Provider.Service s) {
+            super.putService(s);
+            services.add(s);
+        }
+
+        public void removeService(Provider.Service s) {
+            super.removeService(s);
+            services.remove(s);
+        }
+
+        public int getNumServices() {
+            return services.size();
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SignatureException2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SignatureException2Test.java
new file mode 100644
index 0000000..4df1af0
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SignatureException2Test.java
@@ -0,0 +1,44 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.SignatureException;
+
+public class SignatureException2Test extends junit.framework.TestCase {
+
+    /**
+     * @tests java.security.SignatureException#SignatureException()
+     */
+    public void test_Constructor() {
+        // Test for method java.security.SignatureException()
+        SignatureException e = new SignatureException();
+        assertEquals("Failed toString test for constructed instance", "java.security.SignatureException", e
+                .toString());
+    }
+
+    /**
+     * @tests java.security.SignatureException#SignatureException(java.lang.String)
+     */
+    public void test_ConstructorLjava_lang_String() {
+        // Test for method java.security.SignatureException(java.lang.String)
+        SignatureException e = new SignatureException("test message");
+        assertEquals("Failed toString test for constructed instance", 
+                        "java.security.SignatureException: test message", e
+                .toString());
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SignatureExceptionTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SignatureExceptionTest.java
new file mode 100644
index 0000000..70b2754
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SignatureExceptionTest.java
@@ -0,0 +1,188 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.SignatureException;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>SignatureException</code> class constructors and methods.
+ * 
+ */
+public class SignatureExceptionTest extends TestCase {
+
+    public static void main(String[] args) {
+    }
+
+    /**
+     * Constructor for SignatureExceptionTests.
+     * 
+     * @param arg0
+     */
+    public SignatureExceptionTest(String arg0) {
+        super(arg0);
+    }
+
+    private static String[] msgs = {
+            "",
+            "Check new message",
+            "Check new message Check new message Check new message Check new message Check new message" };
+
+    private static Throwable tCause = new Throwable("Throwable for exception");
+
+    /**
+     * Test for <code>SignatureException()</code> constructor Assertion:
+     * constructs SignatureException with no detail message
+     */
+    public void testSignatureException01() {
+        SignatureException tE = new SignatureException();
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>SignatureException(String)</code> constructor Assertion:
+     * constructs SignatureException with detail message msg. Parameter
+     * <code>msg</code> is not null.
+     */
+    public void testSignatureException02() {
+        SignatureException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new SignatureException(msgs[i]);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+
+    /**
+     * Test for <code>SignatureException(String)</code> constructor Assertion:
+     * constructs SignatureException when <code>msg</code> is null
+     */
+    public void testSignatureException03() {
+        String msg = null;
+        SignatureException tE = new SignatureException(msg);
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>SignatureException(Throwable)</code> constructor
+     * Assertion: constructs SignatureException when <code>cause</code> is
+     * null
+     */
+    public void testSignatureException04() {
+        Throwable cause = null;
+        SignatureException tE = new SignatureException(cause);
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>SignatureException(Throwable)</code> constructor
+     * Assertion: constructs SignatureException when <code>cause</code> is not
+     * null
+     */
+    public void testSignatureException05() {
+        SignatureException tE = new SignatureException(tCause);
+        if (tE.getMessage() != null) {
+            String toS = tCause.toString();
+            String getM = tE.getMessage();
+            assertTrue("getMessage() should contain ".concat(toS), (getM
+                    .indexOf(toS) != -1));
+        }
+        assertNotNull("getCause() must not return null", tE.getCause());
+        assertEquals("getCause() must return ".concat(tCause.toString()), tE
+                .getCause(), tCause);
+    }
+
+    /**
+     * Test for <code>SignatureException(String, Throwable)</code> constructor
+     * Assertion: constructs SignatureException when <code>cause</code> is
+     * null <code>msg</code> is null
+     */
+    public void testSignatureException06() {
+        SignatureException tE = new SignatureException(null, null);
+        assertNull("getMessage() must return null", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>SignatureException(String, Throwable)</code> constructor
+     * Assertion: constructs SignatureException when <code>cause</code> is
+     * null <code>msg</code> is not null
+     */
+    public void testSignatureException07() {
+        SignatureException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new SignatureException(msgs[i], null);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+
+    /**
+     * Test for <code>SignatureException(String, Throwable)</code> constructor
+     * Assertion: constructs SignatureException when <code>cause</code> is not
+     * null <code>msg</code> is null
+     */
+    public void testSignatureException08() {
+        SignatureException tE = new SignatureException(null, tCause);
+        if (tE.getMessage() != null) {
+            String toS = tCause.toString();
+            String getM = tE.getMessage();
+            assertTrue("getMessage() must should ".concat(toS), (getM
+                    .indexOf(toS) != -1));
+        }
+        assertNotNull("getCause() must not return null", tE.getCause());
+        assertEquals("getCause() must return ".concat(tCause.toString()), tE
+                .getCause(), tCause);
+    }
+
+    /**
+     * Test for <code>SignatureException(String, Throwable)</code> constructor
+     * Assertion: constructs SignatureException when <code>cause</code> is not
+     * null <code>msg</code> is not null
+     */
+    public void testSignatureException09() {
+        SignatureException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new SignatureException(msgs[i], tCause);
+            String getM = tE.getMessage();
+            String toS = tCause.toString();
+            if (msgs[i].length() > 0) {
+                assertTrue("getMessage() must contain ".concat(msgs[i]), getM
+                        .indexOf(msgs[i]) != -1);
+                if (!getM.equals(msgs[i])) {
+                    assertTrue("getMessage() should contain ".concat(toS), getM
+                            .indexOf(toS) != -1);
+                }
+            }
+            assertNotNull("getCause() must not return null", tE.getCause());
+            assertEquals("getCause() must return ".concat(tCause.toString()),
+                    tE.getCause(), tCause);
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SignatureSpiTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SignatureSpiTest.java
new file mode 100644
index 0000000..418f5d1
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SignatureSpiTest.java
@@ -0,0 +1,103 @@
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureSpi;
+
+import junit.framework.TestCase;
+
+public class SignatureSpiTest extends TestCase {
+
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    public void testClone() {
+        MySignatureSpi1 ss1 = new MySignatureSpi1();
+        try {
+            MySignatureSpi1 ssc1 = (MySignatureSpi1) ss1.clone();
+            assertTrue(ss1 != ssc1);
+        } catch (CloneNotSupportedException e) {
+            fail("Unexpected CloneNotSupportedException " + e.getMessage());
+        }
+
+        
+        MySignatureSpi2 ss2 = new MySignatureSpi2();
+        try {
+            ss2.clone();
+            fail("CloneNotSupportedException expected ");
+        } catch (CloneNotSupportedException e) {
+            // expected
+        }
+    }
+
+    class MySignatureSpi1 extends SignatureSpi implements Cloneable {
+        public Object engineGetParameter(String param) {
+            return null;
+        }
+
+        public Object clone() throws CloneNotSupportedException {
+            return super.clone();
+        }
+        
+        public void engineInitSign(PrivateKey privateKey) {
+        }
+
+        public void engineInitVerify(PublicKey publicKey) {
+        }
+
+        public void engineSetParameter(String param, Object value) {
+        }
+
+        public byte[] engineSign() {
+            return null;
+        }
+
+        public void engineUpdate(byte b) {
+        }
+
+        public void engineUpdate(byte[] b, int off, int len) {
+        }
+
+        public boolean engineVerify(byte[] sigBytes) {
+            return false;
+        }
+    }
+
+    class MySignatureSpi2 extends SignatureSpi {
+        public Object engineGetParameter(String param) {
+            return null;
+        }
+        
+        public Object clone() throws CloneNotSupportedException {
+            return super.clone();
+        }
+        
+        public void engineInitSign(PrivateKey privateKey) {
+        }
+
+        public void engineInitVerify(PublicKey publicKey) {
+        }
+
+        public void engineSetParameter(String param, Object value) {
+        }
+
+        public byte[] engineSign() {
+            return null;
+        }
+
+        public void engineUpdate(byte b) {
+        }
+
+        public void engineUpdate(byte[] b, int off, int len) {
+        }
+
+        public boolean engineVerify(byte[] sigBytes) {
+            return false;
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SignatureTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SignatureTest.java
new file mode 100644
index 0000000..c1eabf4
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SignatureTest.java
@@ -0,0 +1,372 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris V. Kuznetsov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+
+import org.apache.harmony.security.tests.support.MySignature1;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>Signature</code> constructor and methods
+ * 
+ */
+public class SignatureTest extends TestCase {
+
+    /*
+     * Class under test for Signature(String)
+     */
+    public void testConstructor() {
+        String [] algorithms = { "SHA256WITHRSA", "NONEWITHDSA", "SHA384WITHRSA",
+            "MD2WITHRSA", "MD5ANDSHA1WITHRSA", "SHA512WITHRSA",
+            "SHA1WITHRSA", "SHA1WITHDSA", "MD5WITHRSA" };
+        for (int i = 0; i < algorithms.length; i ++) {
+            MySignature1 s = new MySignature1(algorithms[i]);
+            assertEquals(algorithms[i],s.getAlgorithm());
+            assertNull(s.getProvider());
+            assertEquals(0, s.getState());
+        }
+        
+        MySignature1 s1 = new MySignature1(null);
+        assertNull(s1.getAlgorithm());
+        assertNull(s1.getProvider());
+        assertEquals(0, s1.getState());
+    
+        MySignature1 s2 = new MySignature1("ABCD@#&^%$)(*&");
+        assertEquals("ABCD@#&^%$)(*&", s2.getAlgorithm());
+        assertNull(s2.getProvider());
+        assertEquals(0, s2.getState());
+    }
+    
+    /*
+     * Class under test for Object clone()
+     */
+    public void testClone() {
+        MySignature1 s = new MySignature1("ABC");
+        try {
+            s.clone();
+            fail("No expected CloneNotSupportedException");
+        } catch (CloneNotSupportedException e) {    
+        }    
+    }
+
+    public void testGetProvider() {
+        MySignature1 s = new MySignature1("ABC");
+        
+        assertEquals("state", MySignature1.UNINITIALIZED, s.getState());
+        assertNull("provider", s.getProvider());
+    }
+
+    public void testGetAlgorithm() {
+        MySignature1 s = new MySignature1("ABC");
+
+        assertEquals("state", MySignature1.UNINITIALIZED, s.getState());
+        assertEquals("algorithm", "ABC", s.getAlgorithm());
+    }
+
+    /*
+     * Class under test for void initVerify(PublicKey)
+     */
+    public void testInitVerifyPublicKey() throws InvalidKeyException {
+        MySignature1 s = new MySignature1("ABC");
+
+        s.initVerify(new MyPublicKey());
+        assertEquals("state", MySignature1.VERIFY, s.getState());
+        assertTrue("initVerify() failed", s.runEngineInitVerify);
+    }
+
+    /*
+     * Class under test for void initVerify(Certificate)
+     */
+    public void testInitVerifyCertificate() throws InvalidKeyException {
+        MySignature1 s = new MySignature1("ABC");
+
+        s.initVerify(new MyCertificate());
+        assertEquals("state", MySignature1.VERIFY, s.getState());
+        assertTrue("initVerify() failed", s.runEngineInitVerify);
+    }
+
+    /*
+     * Class under test for void initSign(PrivateKey)
+     */
+    public void testInitSignPrivateKey() throws InvalidKeyException {
+        MySignature1 s = new MySignature1("ABC");
+
+        s.initSign(new MyPrivateKey());
+        assertEquals("state", MySignature1.SIGN, s.getState());
+        assertTrue("initSign() failed", s.runEngineInitSign);
+    }
+
+    /*
+     * Class under test for void initSign(PrivateKey, SecureRandom)
+     */
+    public void testInitSignPrivateKeySecureRandom() throws InvalidKeyException {
+        MySignature1 s = new MySignature1("ABC");
+
+        s.initSign(new MyPrivateKey(), new SecureRandom());
+        assertEquals("state", MySignature1.SIGN, s.getState());
+        assertTrue("initSign() failed", s.runEngineInitSign);
+    }
+
+    /*
+     * Class under test for byte[] sign()
+     */
+    public void testSign() throws Exception {
+        MySignature1 s = new MySignature1("ABC");
+        try {
+            s.sign();
+            fail("No expected SignatureException");
+        } catch (SignatureException e) {        
+        }
+
+        s.initVerify(new MyPublicKey());
+        
+        try {
+            s.sign();
+            fail("No expected SignatureException");
+        } catch (SignatureException e) {        
+        }
+        
+        s.initSign(new MyPrivateKey());
+        s.sign();
+        assertEquals("state", MySignature1.SIGN, s.getState());
+        assertTrue("sign() failed", s.runEngineSign);
+    }
+
+    /*
+     * Class under test for sign(byte[], offset, len)
+     */
+    public void testSignbyteintint() throws Exception {
+        MySignature1 s = new MySignature1("ABC");
+        byte[] outbuf = new byte [10];
+        try {
+            s.sign(outbuf, 0, outbuf.length);
+            fail("No expected SignatureException");
+        } catch (SignatureException e) {        
+        }
+
+        s.initVerify(new MyPublicKey());
+        
+        try {
+            s.sign(outbuf, 0, outbuf.length);
+            fail("No expected SignatureException");
+        } catch (SignatureException e) {        
+        }
+        
+        s.initSign(new MyPrivateKey());
+        assertEquals(s.getBufferLength(), s.sign(outbuf, 0, outbuf.length));
+        assertEquals("state", MySignature1.SIGN, s.getState());
+        assertTrue("sign() failed", s.runEngineSign);
+    }
+
+    
+    /*
+     * Class under test for boolean verify(byte[])
+     */
+    public void testVerifybyteArray() throws Exception {
+        MySignature1 s = new MySignature1("ABC");
+        byte[] b = {1, 2, 3, 4};
+        try {
+            s.verify(b);
+            fail("No expected SignatureException");
+        } catch (SignatureException e) {        
+        }
+
+        s.initSign(new MyPrivateKey());
+        try {
+            s.verify(b);
+            fail("No expected SignatureException");
+        } catch (SignatureException e) {        
+        }
+        
+        s.initVerify(new MyPublicKey());
+        s.verify(b);
+        assertEquals("state", MySignature1.VERIFY, s.getState());
+        assertTrue("verify() failed", s.runEngineVerify);
+    }
+
+    /*
+     * Class under test for boolean verify(byte[], int, int)
+     */
+    public void testVerifybyteArrayintint() throws Exception {
+        MySignature1 s = new MySignature1("ABC");
+        byte[] b = {1, 2, 3, 4};
+        try {
+            s.verify(b, 0, 3);
+            fail("No expected SignatureException");
+        } catch (SignatureException e) {        
+        }
+
+        s.initSign(new MyPrivateKey());
+
+        try {
+            s.verify(b, 0, 3);
+            fail("No expected SignatureException");
+        } catch (SignatureException e) {        
+        }
+        
+        s.initVerify(new MyPublicKey());
+        
+        try {
+            s.verify(b, 0, 5);
+            fail("No expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {        
+        }
+        
+        s.verify(b, 0, 3);
+        assertEquals("state", MySignature1.VERIFY, s.getState());
+        assertTrue("verify() failed", s.runEngineVerify);
+    }
+
+    /*
+     * Class under test for void update(byte)
+     */
+    public void testUpdatebyte() throws Exception {
+        MySignature1 s = new MySignature1("ABC");
+        try {
+            s.update((byte)1);
+            fail("No expected SignatureException");
+        } catch (SignatureException e) {        
+        }
+
+        s.initVerify(new MyPublicKey());
+        s.update((byte) 1);
+        s.initSign(new MyPrivateKey());
+        s.update((byte) 1);
+
+        assertEquals("state", MySignature1.SIGN, s.getState());
+        assertTrue("update() failed", s.runEngineUpdate1);
+    }
+
+    /*
+     * Class under test for void update(byte[])
+     */
+    public void testUpdatebyteArray() throws Exception {
+        MySignature1 s = new MySignature1("ABC");
+        byte[] b = {1, 2, 3, 4};
+        try {
+            s.update(b);
+            fail("No expected SignatureException");
+        } catch (SignatureException e) {        
+        }
+
+        s.initVerify(new MyPublicKey());
+        s.update(b);
+        s.initSign(new MyPrivateKey());
+        s.update(b);
+
+        assertEquals("state", MySignature1.SIGN, s.getState());
+        assertTrue("update() failed", s.runEngineUpdate2);
+    }
+
+    /*
+     * Class under test for void update(byte[], int, int)
+     */
+    public void testUpdatebyteArrayintint() throws Exception {
+        MySignature1 s = new MySignature1("ABC");
+        byte[] b = {1, 2, 3, 4};
+        try {
+            s.update(b, 0, 3);
+            fail("No expected SignatureException");
+        } catch (SignatureException e) {        
+        }
+
+        s.initVerify(new MyPublicKey());
+        s.update(b, 0, 3);
+        s.initSign(new MyPrivateKey());
+        s.update(b, 0, 3);
+
+        assertEquals("state", MySignature1.SIGN, s.getState());
+        assertTrue("update() failed", s.runEngineUpdate2);
+    }
+
+    /*
+     * Class under test for void setParameter(String, Object)
+     */
+    @SuppressWarnings("deprecation")
+    public void testSetParameterStringObject() {
+        MySignature1 s = new MySignature1("ABC");
+        s.setParameter("aaa", new Object());
+    }
+
+    /*
+     * Class under test for void setParameter(AlgorithmParameterSpec)
+     */
+    public void testSetParameterAlgorithmParameterSpec() throws InvalidAlgorithmParameterException {
+        MySignature1 s = new MySignature1("ABC");
+        try {
+            s.setParameter((java.security.spec.AlgorithmParameterSpec)null);
+            fail("No expected UnsupportedOperationException");
+        } catch (UnsupportedOperationException e){    
+        }
+    }
+    @SuppressWarnings("deprecation")
+    public void testGetParameter() {
+        MySignature1 s = new MySignature1("ABC");
+        s.getParameter("aaa");
+    }
+    
+    private class MyKey implements Key {
+        public String getFormat() {
+            return "123";
+        }
+        public byte[] getEncoded() {
+            return null;
+        }
+        public String getAlgorithm() {
+            return "aaa";
+        }        
+    }
+    
+    private class MyPublicKey extends MyKey implements PublicKey {}
+
+    private class MyPrivateKey extends MyKey implements PrivateKey {}
+    
+    private class MyCertificate extends java.security.cert.Certificate {    
+        public  MyCertificate() {
+            super("MyCertificateType");
+        }
+        
+        public PublicKey getPublicKey() {
+            return new MyPublicKey();
+        }
+        
+        public byte[] getEncoded() {
+            return null;
+        }
+        public void verify(PublicKey key) {}
+        
+        public void verify(PublicKey key, String sigProvider) {}
+        
+        public String toString() {
+            return "MyCertificate";
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SignedObjectTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SignedObjectTest.java
new file mode 100644
index 0000000..74df871
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SignedObjectTest.java
@@ -0,0 +1,102 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris V. Kuznetsov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.SignedObject;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Properties;
+
+import org.apache.harmony.security.tests.support.TestKeyPair;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>SignedObject</code> constructor and methods
+ * 
+ */
+public class SignedObjectTest extends TestCase {
+
+    public void testSignedObject() {
+        Signature sig = null;
+        TestKeyPair tkp = null;
+        Properties prop;
+        
+        try {
+            sig = Signature.getInstance("SHA1withDSA");        
+        } catch (NoSuchAlgorithmException e) {
+            fail(e.toString());
+        }
+        
+        try {
+            tkp = new TestKeyPair("DSA");
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+            return;
+        }
+        prop = new Properties();
+        prop.put("aaa", "bbb");
+        SignedObject so = null;
+        try {
+            so = new SignedObject(prop, tkp.getPrivate(), sig);
+        } catch (IOException e) {
+               fail(e.toString());  
+        } catch (SignatureException e) {   
+               fail(e.toString());  
+        } catch (InvalidKeyException e) {
+               fail(e.toString());  
+        } catch (InvalidKeySpecException e) {
+              fail(e.toString());
+        }
+
+        assertEquals("SHA1withDSA", so.getAlgorithm());
+ 
+        try {
+            assertEquals(so.getObject(), prop);          
+        } catch (ClassNotFoundException e) {
+               fail(e.toString());  
+        } catch (IOException e) {
+               fail(e.toString());  
+        }
+        try {
+            if (!so.verify(tkp.getPublic(), sig)) {
+                fail("verify() failed");
+            }    
+        } catch (SignatureException e) {
+            fail(e.toString());          
+        } catch (InvalidKeyException e) {
+               fail(e.toString());             
+        } catch (InvalidKeySpecException e) {
+               fail(e.toString()); 
+        }
+        
+        if (so.getSignature() == null) {
+            fail("signature is null");
+        }             
+    }
+    
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SignerTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SignerTest.java
new file mode 100644
index 0000000..685dd78
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/SignerTest.java
@@ -0,0 +1,183 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Aleksei Y. Semenov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.IdentityScope;
+import java.security.KeyPair;
+import java.security.Permission;
+import java.security.Permissions;
+import java.security.SecurityPermission;
+import java.security.Signer;
+
+import org.apache.harmony.security.tests.support.PrivateKeyStub;
+import org.apache.harmony.security.tests.support.PublicKeyStub;
+import org.apache.harmony.security.tests.support.SignerStub;
+
+
+import junit.framework.TestCase;
+
+
+
+/**
+ * tests for class Signer
+ * 
+ */
+@SuppressWarnings("deprecation")
+public class SignerTest extends TestCase {
+
+    public static class MySecurityManager extends SecurityManager {
+        public Permissions denied = new Permissions(); 
+        public void checkPermission(Permission permission){
+            if (denied!=null && denied.implies(permission)) throw new SecurityException();
+        }
+    }    
+    
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(SignerTest.class);
+    }
+
+    /**
+     * Constructor for SignerTest.
+     * @param arg0
+     */
+    public SignerTest(String arg0) {
+        super(arg0);
+    }
+
+    /**
+     * @tests java.security.Signer#toString()
+     */
+    public void test_toString() throws Exception {
+        Signer s1 = new SignerStub("testToString1");
+        assertEquals("[Signer]testToString1", s1.toString());
+
+        Signer s2 = new SignerStub("testToString2", IdentityScope.getSystemScope());
+        s2.toString();
+
+        KeyPair kp = new KeyPair(new PublicKeyStub("public", "SignerTest.testToString", null), new PrivateKeyStub("private", "SignerTest.testToString", null));
+        s1.setKeyPair(kp);
+        s1.toString();
+
+        s2.setKeyPair(kp);
+        s2.toString();
+    }
+
+    /**
+     * verify Signer() creates instance
+     */
+    public void testSigner() {
+        Signer s = new SignerStub();
+        assertNotNull(s);
+        //assertNull(s.getName(), s.getName());      
+        assertNull(s.getPrivateKey());
+    }
+
+    /**
+     * verify Signer(String) creates instance
+     */
+    public void testSignerString() throws Exception {
+        Signer s = new SignerStub("sss3");
+        assertNotNull(s);
+        assertEquals("sss3", s.getName());      
+        assertNull(s.getPrivateKey());
+    }
+
+    /**
+     * verify  Signer(String, IdentityScope) creates instance
+     */
+    public void testSignerStringIdentityScope() throws Exception {
+        Signer s = new SignerStub("sss4", IdentityScope.getSystemScope());
+        assertNotNull(s);
+        assertEquals("sss4", s.getName());
+        assertSame(IdentityScope.getSystemScope(), s.getScope());
+        assertNull(s.getPrivateKey());
+    }
+
+    /**
+     * verify Signer.getPrivateKey() returns null or private key
+     */
+    public void testGetPrivateKey() throws Exception {
+        byte [] privateKeyData = { 1, 2, 3, 4, 5};  
+        PrivateKeyStub privateKey = new PrivateKeyStub("private", "fff", privateKeyData);
+        PublicKeyStub publicKey = new PublicKeyStub("public", "fff", null);
+        KeyPair kp = new KeyPair(publicKey, privateKey);
+        
+        Signer s = new SignerStub("sss5");
+        
+        assertNull(s.getPrivateKey());
+        
+        s.setKeyPair(kp);                
+        assertSame(privateKey, s.getPrivateKey());
+    }
+    
+    /**
+     * verify Signer.getPrivateKey() throws SecurityException if permission is denied
+     */
+    public void testGetPrivateKey_denied() throws Exception {
+        MySecurityManager sm = new MySecurityManager();
+        sm.denied.add(new SecurityPermission("getSignerPrivateKey"));
+        System.setSecurityManager(sm);
+        try {
+            Signer s = new SignerStub("sss6");
+            s.setKeyPair(new KeyPair(new PublicKeyStub("public", "fff", null), new PrivateKeyStub("private", "fff", null)));
+            try {
+                s.getPrivateKey();
+                fail("SecurityException should be thrown");
+            } catch (SecurityException ok) {}            
+        } finally {
+            System.setSecurityManager(null);
+        }
+        
+    }
+
+    /**
+     * @tests java.security.Signer#setKeyPair(java.security.KeyPair) 
+     */
+    public void test_setKeyPairLjava_security_KeyPair() throws Exception {
+        
+        // Regression for HARMONY-2408
+        // test: NullPointerException if pair is null
+        try {
+            new SignerStub("name").setKeyPair(null);
+            fail("No expected NullPointerException");
+        } catch (NullPointerException e) {
+        }
+        
+        // test: SecurityException if permission is denied
+        SecurityManager oldSm = System.getSecurityManager();
+        MySecurityManager sm = new MySecurityManager();
+        sm.denied.add(new SecurityPermission("setSignerKeyPair"));
+        System.setSecurityManager(sm);
+        try {
+            Signer s = new SignerStub("sss7");
+            try {
+                s.setKeyPair(new KeyPair(new PublicKeyStub("public", "fff",
+                        null), new PrivateKeyStub("private", "fff", null)));
+                fail("SecurityException should be thrown");
+            } catch (SecurityException ok) {
+            }
+        } finally {
+            System.setSecurityManager(oldSm);
+        }        
+    }
+
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/TimestampTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/TimestampTest.java
new file mode 100644
index 0000000..c3d684e
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/TimestampTest.java
@@ -0,0 +1,122 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Alexander V. Astapchuk
+ * @version $Revision$
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.Timestamp;
+import java.security.cert.CertPath;
+import java.util.Date;
+
+import org.apache.harmony.security.tests.support.cert.MyCertPath;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>Timestamp</code> class fields and methods
+ * 
+ */
+
+public class TimestampTest extends TestCase {
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(TimestampTest.class);
+    }
+
+    private Date now = new Date();
+
+    private static final byte[] encoding = { 1, 2, 3 };
+
+    private CertPath cpath = new MyCertPath(encoding);
+
+    public void testTimestamp() {
+        try {
+            new Timestamp(null, cpath);
+            fail("null was accepted");
+        } catch (NullPointerException ex) { /* ok */
+        }
+
+        try {
+            new Timestamp(now, null);
+            fail("null was accepted");
+            return;
+        } catch (NullPointerException ex) { /* ok */
+        }
+    }
+
+    /*
+     * Class under test for boolean equals(Object)
+     */
+    public void testEqualsObject() {
+        Timestamp one = new Timestamp(now, cpath);
+        Timestamp two = new Timestamp(now, cpath);
+
+        assertTrue(one.equals(one));
+        assertTrue(one.equals(two));
+        assertTrue(two.equals(one));
+        assertFalse(one.equals(null));
+        assertFalse(one.equals(new Object()));
+
+        Timestamp two1 = new Timestamp(new Date(9999), cpath);
+        assertFalse(one.equals(two1));
+        assertTrue(two1.equals(two1));
+    }
+
+    public void testGetSignerCertPath() {
+        assertSame(new Timestamp(now, cpath).getSignerCertPath(), cpath);
+    }
+
+    public void testGetTimestamp() {
+        Timestamp t = new Timestamp(now, cpath);
+        assertEquals(now, t.getTimestamp());
+        assertNotSame(now, t.getTimestamp());
+    }
+
+    /*
+     * Class under test for String toString()
+     */
+    public void testToString() {
+        new Timestamp(now, cpath).toString();
+    }
+
+    /*
+     * Class under test for String hashCode()
+     */
+    public void testHashCode() {
+        Timestamp one = new Timestamp(now, cpath);
+        Timestamp two = new Timestamp(now, cpath);
+        Timestamp three = new Timestamp(now, new MyCertPath(new byte[] { 10,
+                20, 30 }));
+        Timestamp four = null;
+        
+        assertTrue(one.hashCode() == two.hashCode());
+        assertTrue(one.hashCode() != three.hashCode());
+        assertTrue(two.hashCode() != three.hashCode());
+        
+        try {
+            four.hashCode();
+            fail("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // expected
+        }
+
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/UnrecoverableEntryExceptionTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/UnrecoverableEntryExceptionTest.java
new file mode 100644
index 0000000..c18c964
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/UnrecoverableEntryExceptionTest.java
@@ -0,0 +1,73 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.UnrecoverableEntryException;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>UnrecoverableEntryException</code> class
+ * 
+ */
+
+public class UnrecoverableEntryExceptionTest extends TestCase {
+
+    /**
+     * Constructor for UnrecoverableEntryExceptionTest.
+     * 
+     * @param arg0
+     */
+    public UnrecoverableEntryExceptionTest(String arg0) {
+        super(arg0);
+    }
+
+    static String[] msgs = {
+            "",
+            "Check new message",
+            "Check new message Check new message Check new message Check new message Check new message" };
+
+    static String errNotExc = "Not UnrecoverableEntryException object";
+
+    /*
+     * Class under test for void UnrecoverableEntryException()
+     */
+    public void testUnrecoverableEntryException() {
+        UnrecoverableEntryException tE = new UnrecoverableEntryException();
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /*
+     * Class under test for void UnrecoverableEntryException(String)
+     */
+    public void testUnrecoverableEntryExceptionString() {
+        UnrecoverableEntryException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new UnrecoverableEntryException(msgs[i]);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/UnrecoverableKeyException2Test.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/UnrecoverableKeyException2Test.java
new file mode 100644
index 0000000..36cfbbd
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/UnrecoverableKeyException2Test.java
@@ -0,0 +1,46 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.security.UnrecoverableKeyException;
+
+public class UnrecoverableKeyException2Test extends junit.framework.TestCase {
+
+    /**
+     * @tests java.security.UnrecoverableKeyException#UnrecoverableKeyException()
+     */
+    public void test_Constructor() {
+        // Test for method java.security.UnrecoverableKeyException()
+        UnrecoverableKeyException e = new UnrecoverableKeyException();
+        assertEquals("Failed toString test for constructed instance", "java.security.UnrecoverableKeyException", e
+                .toString());
+    }
+
+    /**
+     * @tests java.security.UnrecoverableKeyException#UnrecoverableKeyException(java.lang.String)
+     */
+    public void test_ConstructorLjava_lang_String() {
+        // Test for method
+        // java.security.UnrecoverableKeyException(java.lang.String)
+        UnrecoverableKeyException e = new UnrecoverableKeyException(
+                "test message");
+        assertEquals("Failed toString test for constructed instance",
+                "java.security.UnrecoverableKeyException: test message", e
+                        .toString());
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/UnrecoverableKeyExceptionTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/UnrecoverableKeyExceptionTest.java
new file mode 100644
index 0000000..66a077c
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/UnrecoverableKeyExceptionTest.java
@@ -0,0 +1,92 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Vera Y. Petrashkova
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.tests.java.security;
+import java.security.UnrecoverableKeyException;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>UnrecoverableKeyException</code> class constructors and
+ * methods.
+ * 
+ */
+public class UnrecoverableKeyExceptionTest extends TestCase {
+
+    public static void main(String[] args) {
+    }
+
+    /**
+     * Constructor for UnrecoverableKeyExceptionTests.
+     * 
+     * @param arg0
+     */
+    public UnrecoverableKeyExceptionTest(String arg0) {
+        super(arg0);
+    }
+
+    static String[] msgs = {
+            "",
+            "Check new message",
+            "Check new message Check new message Check new message Check new message Check new message" };
+
+    static Throwable tCause = new Throwable("Throwable for exception");
+
+    /**
+     * Test for <code>UnrecoverableKeyException()</code> constructor
+     * Assertion: constructs UnrecoverableKeyException with no detail message
+     */
+    public void testUnrecoverableKeyException01() {
+        UnrecoverableKeyException tE = new UnrecoverableKeyException();
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+    /**
+     * Test for <code>UnrecoverableKeyException(String)</code> constructor
+     * Assertion: constructs UnrecoverableKeyException with detail message msg.
+     * Parameter <code>msg</code> is not null.
+     */
+    public void testUnrecoverableKeyException02() {
+        UnrecoverableKeyException tE;
+        for (int i = 0; i < msgs.length; i++) {
+            tE = new UnrecoverableKeyException(msgs[i]);
+            assertEquals("getMessage() must return: ".concat(msgs[i]), tE
+                    .getMessage(), msgs[i]);
+            assertNull("getCause() must return null", tE.getCause());
+        }
+    }
+
+    /**
+     * Test for <code>UnrecoverableKeyException(String)</code> constructor
+     * Assertion: constructs UnrecoverableKeyException when <code>msg</code>
+     * is null
+     */
+    public void testUnrecoverableKeyException03() {
+        String msg = null;
+        UnrecoverableKeyException tE = new UnrecoverableKeyException(msg);
+        assertNull("getMessage() must return null.", tE.getMessage());
+        assertNull("getCause() must return null", tE.getCause());
+    }
+
+}
diff --git a/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/UnresolvedPermissionTest.java b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/UnresolvedPermissionTest.java
new file mode 100644
index 0000000..ae8f50b
--- /dev/null
+++ b/libcore/security/src/test/java/org/apache/harmony/security/tests/java/security/UnresolvedPermissionTest.java
@@ -0,0 +1,304 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.harmony.security.tests.java.security;
+
+import java.io.Serializable;
+import java.security.AllPermission;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.SecurityPermission;
+import java.security.UnresolvedPermission;
+import java.security.cert.Certificate;
+import java.util.Arrays;
+import java.util.Enumeration;
+import org.apache.harmony.testframework.serialization.SerializationTest.SerializableAssert;
+import org.apache.harmony.testframework.serialization.SerializationTest;
+
+import tests.util.SerializationTester;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests for <code>UnresolvedPermission</code> class fields and methods
+ * 
+ */
+
+public class UnresolvedPermissionTest extends TestCase {
+
+    /**
+     * Creates an Object with given name, type, action, certificates. Empty or
+     * null type is not allowed - exception should be thrown.
+     */
+    public void testCtor() {
+        String type = "laskjhlsdk 2345346";
+        String name = "^%#UHVKU^%V  887y";
+        String action = "JHB ^%(*&T klj3h4";
+        UnresolvedPermission up = new UnresolvedPermission(type, name, action,
+                null);
+        assertEquals(type, up.getName());
+        assertEquals("", up.getActions());
+        assertEquals("(unresolved " + type + " " + name + " " + action + ")",
+                up.toString());
+
+        up = new UnresolvedPermission(type, null, null, null);
+        assertEquals(type, up.getName());
+        assertEquals("", up.getActions());
+        assertEquals("(unresolved " + type + " null null)", up.toString());
+
+        up = new UnresolvedPermission(type, "", "",
+                new java.security.cert.Certificate[0]);
+        assertEquals(type, up.getName());
+        assertEquals("", up.getActions());
+        assertEquals("(unresolved " + type + "  )", up.toString());
+
+        try {
+            new UnresolvedPermission(null, name, action, null);
+            fail("No expected NullPointerException");
+        } catch (NullPointerException ok) {
+        }
+
+        // Regression for HARMONY-733
+        up = new UnresolvedPermission("", "name", "action", null);
+        assertEquals("", up.getName());
+    }
+
+    /**
+     * UnresolvedPermission never implies any other permission.
+     */
+    public void testImplies() {
+        UnresolvedPermission up = new UnresolvedPermission(
+                "java.security.SecurityPermission", "a.b.c", null, null);
+        assertFalse(up.implies(up));
+        assertFalse(up.implies(new AllPermission()));
+        assertFalse(up.implies(new SecurityPermission("a.b.c")));
+    }
+
+    public void testSerialization() throws Exception {
+        UnresolvedPermission up = new UnresolvedPermission(
+                "java.security.SecurityPermission", "a.b.c", "actions", null);
+        assertEquals("java.security.SecurityPermission", up.getUnresolvedType());
+        assertEquals("a.b.c", up.getUnresolvedName());
+        assertEquals("actions", up.getUnresolvedActions());
+        assertNull(up.getUnresolvedCerts());
+
+        UnresolvedPermission deserializedUp = (UnresolvedPermission) SerializationTester
+                .getDeserilizedObject(up);
+        assertEquals("java.security.SecurityPermission", deserializedUp
+                .getUnresolvedType());
+        assertEquals("a.b.c", deserializedUp.getUnresolvedName());
+        assertEquals("actions", deserializedUp.getUnresolvedActions());
+        assertNull(deserializedUp.getUnresolvedCerts());
+    }
+
+    public void testSerialization_Compatibility() throws Exception {
+        UnresolvedPermission up = new UnresolvedPermission(
+                "java.security.SecurityPermission", "a.b.c", "actions", null);
+        assertEquals("java.security.SecurityPermission", up.getUnresolvedType());
+        assertEquals("a.b.c", up.getUnresolvedName());
+        assertEquals("actions", up.getUnresolvedActions());
+        assertNull(up.getUnresolvedCerts());
+
+        SerializationTest.verifyGolden(this, up, new SerializableAssert() {
+            public void assertDeserialized(Serializable orig, Serializable ser) {
+                UnresolvedPermission deserializedUp = (UnresolvedPermission) ser;
+                assertEquals("java.security.SecurityPermission", deserializedUp
+                        .getUnresolvedType());
+                assertEquals("a.b.c", deserializedUp.getUnresolvedName());
+                assertEquals("actions", deserializedUp.getUnresolvedActions());
+                assertNull(deserializedUp.getUnresolvedCerts());
+            }
+        });
+    }
+
+    public void testEquals() {
+        UnresolvedPermission up1 = new UnresolvedPermission("type1", "name1",
+                "action1", null);
+        UnresolvedPermission up2 = new UnresolvedPermission("type1", "name1",
+                "action1", null);
+        UnresolvedPermission up3 = new UnresolvedPermission("type3", "name3",
+                "action3", null);
+
+        UnresolvedPermission up4 = null;
+
+        assertTrue(up1.equals(up1));
+        assertTrue(up2.equals(up2));
+        assertTrue(up3.equals(up3));
+
+        assertTrue(!up1.equals(null));
+        assertTrue(!up2.equals(null));
+        assertTrue(!up3.equals(null));
+
+        assertTrue(up1.equals(up2));
+        assertTrue(!up1.equals(up3));
+
+        assertTrue(up2.equals(up1));
+        assertTrue(!up2.equals(up3));
+
+        assertTrue(!up3.equals(up1));
+        assertTrue(!up3.equals(up2));
+
+        try {
+            assertTrue(up4.equals(up1));
+            fail("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // expected
+        }
+
+    }
+
+    public void testGetActions() {
+        UnresolvedPermission up1 = new UnresolvedPermission("type1", "name1",
+                "action1", null);
+        UnresolvedPermission up2 = null;
+
+        assertEquals("", up1.getActions());
+        try {
+            up2.getActions();
+            fail("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public void testGetUnresolvedActions() {
+        UnresolvedPermission up1 = new UnresolvedPermission("type1", "name1",
+                "action1 @#$%^&*", null);
+        UnresolvedPermission up2 = null;
+
+        assertEquals("action1 @#$%^&*", up1.getUnresolvedActions());
+        try {
+            up2.getUnresolvedActions();
+            fail("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public void testGetUnresolvedCerts() {
+        Certificate[] certificate = new java.security.cert.Certificate[0];
+        UnresolvedPermission up1 = new UnresolvedPermission("type1", "name1",
+                "action1 @#$%^&*", null);
+        UnresolvedPermission up2 = null;
+        UnresolvedPermission up3 = new UnresolvedPermission("type3", "name3",
+                "action3", certificate);
+
+        assertNull(up1.getUnresolvedCerts());
+        assertTrue(Arrays.equals(certificate, up3.getUnresolvedCerts()));
+        
+        try {
+            up2.getUnresolvedCerts();
+            fail("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public void testGetUnresolvedName() {
+        UnresolvedPermission up1 = new UnresolvedPermission("type1", "name1!@#$%^&&* )(",
+                "action1 @#$%^&*", null);
+        UnresolvedPermission up2 = null;
+
+        assertEquals("name1!@#$%^&&* )(", up1.getUnresolvedName());
+        try {
+            up2.getUnresolvedName();
+            fail("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public void testGetUnresolvedType() {
+        UnresolvedPermission up1 = new UnresolvedPermission("type1@#$%^&* )(", "name1",
+                "action1", null);
+        UnresolvedPermission up2 = null;
+
+        assertEquals("type1@#$%^&* )(", up1.getUnresolvedType());
+        try {
+            up2.getUnresolvedType();
+            fail("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public void testHashCode() {
+        UnresolvedPermission up1 = new UnresolvedPermission("type1", "name1",
+                "action1", null);
+        UnresolvedPermission up2 = new UnresolvedPermission("type1", "name1",
+                "action1", null);
+        UnresolvedPermission up3 = new UnresolvedPermission("type3", "name3",
+                "action3", null);
+
+        UnresolvedPermission up4 = null;
+
+        assertTrue(up1.hashCode() == up2.hashCode());
+        assertTrue(up1.hashCode() != up3.hashCode());
+        assertTrue(up2.hashCode() != up3.hashCode());
+
+        try {
+            up4.hashCode();
+            fail("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public void testNewPermissionCollection() {
+        UnresolvedPermission up1 = new UnresolvedPermission("type1", "name1",
+                "action1", null);
+        UnresolvedPermission up2 = new UnresolvedPermission("type1", "name1",
+                "action1", null);
+        UnresolvedPermission up3 = null;
+        
+        PermissionCollection pc = up1.newPermissionCollection();
+        assertTrue(!pc.isReadOnly());
+        pc.add(up1);
+        pc.add(up2);
+        Enumeration<Permission> permissions = pc.elements();
+        assertNotNull(permissions);
+        
+        assertTrue("Should imply", !pc.implies(up1));
+        assertTrue("Should not imply", !pc.implies(up3));
+        
+        try {
+            up3.newPermissionCollection();
+            fail("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // expected
+        }
+        
+    }
+
+    public void testToString() {
+        UnresolvedPermission up1 = new UnresolvedPermission("type1", "name1",
+                "action1", null);
+        UnresolvedPermission up2 = new UnresolvedPermission("type1", "name1",
+                "action1", null);
+        UnresolvedPermission up3 = null;
+        assertTrue(up1.toString().contains(""));
+        assertTrue(up2.toString().contains(""));
+        try {
+            up3.toString();
+            fail("NullPointerException expected");
+        }catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+}
diff --git a/libcore/security/src/test/java/tests/api/java/security/AccessControlContextTest.java b/libcore/security/src/test/java/tests/api/java/security/AccessControlContextTest.java
new file mode 100644
index 0000000..9041b07
--- /dev/null
+++ b/libcore/security/src/test/java/tests/api/java/security/AccessControlContextTest.java
@@ -0,0 +1,283 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.api.java.security;
+
+import java.io.File;
+import java.io.FilePermission;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.ProtectionDomain;
+import java.util.PropertyPermission;
+
+import javax.security.auth.Subject;
+import javax.security.auth.SubjectDomainCombiner;
+
+public class AccessControlContextTest extends junit.framework.TestCase {
+
+    /**
+     * @tests java.security.AccessControlContext#AccessControlContext(java.security.ProtectionDomain[])
+     */
+    public void test_Constructor$Ljava_security_ProtectionDomain() {
+        // Test for method
+        // java.security.AccessControlContext(java.security.ProtectionDomain [])
+
+        // Create a permission which is not normally granted
+        final Permission perm = new PropertyPermission("java.class.path",
+                "read");
+        PermissionCollection col = perm.newPermissionCollection();
+        col.add(perm);
+        final ProtectionDomain pd = new ProtectionDomain(null, col);
+        AccessControlContext acc = new AccessControlContext(
+                new ProtectionDomain[] { pd });
+        try {
+            acc.checkPermission(perm);
+        } catch (SecurityException e) {
+            fail("Should have permission");
+        }
+
+        final boolean[] result = new boolean[] { false };
+        Thread th = new Thread(new Runnable() {
+            public void run() {
+                AccessControlContext acc = new AccessControlContext(
+                        new ProtectionDomain[] { pd });
+                try {
+                    acc.checkPermission(perm);
+                    result[0] = true;
+                } catch (SecurityException e) {
+                }
+            }
+        });
+        th.start();
+        try {
+            th.join();
+        } catch (InterruptedException e) {
+            // ignore
+        }
+        assertTrue("Thread should have permission", result[0]);
+    }
+
+    /**
+     * @tests java.security.AccessControlContext#AccessControlContext(java.security.AccessControlContext,
+     *        java.security.DomainCombiner)
+     */
+    public void test_ConstructorLjava_security_AccessControlContextLjava_security_DomainCombiner() {
+        AccessControlContext context = AccessController.getContext();
+        try {
+            new AccessControlContext(context, null);
+        } catch (NullPointerException e) {
+            fail("should not throw NullPointerException");
+        }
+
+        try {
+            new AccessControlContext(context, new SubjectDomainCombiner(
+                    new Subject()));
+        } catch (Exception e) {
+            fail("should not throw Exception");
+        }
+    }
+
+    /**
+     * @tests java.security.AccessControlException#checkPermission(Permission)
+     */
+    public void test_checkPermission() {
+        char s = File.separatorChar;
+        FilePermission perm[] = new FilePermission[7];
+        perm[0] = new FilePermission("test1.file", "write");
+        perm[1] = new FilePermission("test1.file", "read, execute, delete");
+        perm[2] = new FilePermission(s + "tmp" + s + "test" + s + "*",
+                "read, write");
+        perm[3] = new FilePermission(s + "tmp" + s + "test" + s
+                + "collection.file", "read");
+        perm[4] = new FilePermission(s + "windows" + "*", "delete");
+        perm[5] = new FilePermission("aFile.file", "read");
+        perm[6] = new FilePermission("hello.file", "write");
+
+        Permissions perms = new Permissions();
+        for (int i = 0; i < perm.length; i++) {
+            perms.add(perm[i]);
+        }
+        ProtectionDomain pd = new ProtectionDomain(null, perms);
+
+        AccessControlContext acc = new AccessControlContext(
+                new ProtectionDomain[] { pd });
+
+        for (int i = 0; i < perm.length; i++) {
+            try {
+                acc.checkPermission(perm[i]);
+            } catch (SecurityException e) {
+                fail("Should have permission " + perm[i]);
+            }
+        }
+
+        try {
+            acc.checkPermission(new FilePermission("test1.file", "execute"));
+        } catch (SecurityException e) {
+            fail("Should have permission ");
+        }
+
+        try {
+            acc.checkPermission(new FilePermission(s + "tmp" + s + "test" + s
+                    + "hello.file", "read"));
+        } catch (SecurityException e) {
+            fail("Should have permission ");
+        }
+        
+        try {
+            acc.checkPermission(new FilePermission("test2.file", "execute"));
+            fail("SecurityException expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+
+        try {
+            acc.checkPermission(new FilePermission(s + "tmp" + s + "test" + s
+                    + "hello.file", "delete"));
+            fail("SecurityException expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    /**
+     * @tests java.security.AccessControlException#equals()
+     */
+    public void test_equals() {
+        final Permission perm1 = new PropertyPermission("java.class.path",
+                "read");
+        final Permission perm2 = new PropertyPermission("java.path", "write");
+
+        PermissionCollection col1 = perm1.newPermissionCollection();
+        col1.add(perm1);
+        final ProtectionDomain pd1 = new ProtectionDomain(null, col1);
+        AccessControlContext acc1 = new AccessControlContext(
+                new ProtectionDomain[] { pd1 });
+
+        AccessControlContext acc2 = new AccessControlContext(
+                new ProtectionDomain[] { pd1 });
+
+        PermissionCollection col2 = perm2.newPermissionCollection();
+        col2.add(perm2);
+        col2.add(perm2);
+        final ProtectionDomain pd2 = new ProtectionDomain(null, col2);
+        AccessControlContext acc3 = new AccessControlContext(
+                new ProtectionDomain[] { pd2 });
+
+        assertFalse(acc1.equals(null));
+        assertFalse(acc2.equals(null));
+        assertFalse(acc3.equals(null));
+
+        assertTrue(acc1.equals(acc2));
+        assertTrue(acc2.equals(acc1));
+        assertFalse(acc1.equals(acc3));
+        assertFalse(acc2.equals(acc3));
+
+        AccessControlContext context = AccessController.getContext();
+
+        AccessControlContext acc4 = new AccessControlContext(context, null);
+        AccessControlContext acc5 = new AccessControlContext(context,
+                new SubjectDomainCombiner(new Subject()));
+
+        AccessControlContext acc6 = new AccessControlContext(context, null);
+
+        assertFalse(acc4.equals(null));
+        assertFalse(acc5.equals(null));
+
+        assertFalse(acc4.equals(acc5));
+        assertFalse(acc5.equals(acc4));
+
+        assertTrue(acc4.equals(acc6));
+        assertTrue(acc6.equals(acc4));
+    }
+
+    /**
+     * @tests java.security.AccessControlException#getDomainCombiner()
+     */
+    public void test_getDomainCombiner() {
+        AccessControlContext context = AccessController.getContext();
+
+        AccessControlContext acc1 = new AccessControlContext(context, null);
+
+        AccessControlContext acc2 = new AccessControlContext(context,
+                new SubjectDomainCombiner(new Subject()));
+
+        final Permission perm1 = new PropertyPermission("java.class.path",
+                "read");
+
+        PermissionCollection col1 = perm1.newPermissionCollection();
+        col1.add(perm1);
+        final ProtectionDomain pd1 = new ProtectionDomain(null, col1);
+        AccessControlContext acc3 = new AccessControlContext(
+                new ProtectionDomain[] { pd1 });
+
+        assertNull(acc1.getDomainCombiner());
+        assertNotNull(acc2.getDomainCombiner());
+        assertNull(acc3.getDomainCombiner());
+    }
+
+    /**
+     * @tests java.security.AccessControlException#hashCode()
+     */
+    public void test_hashCode() {
+        final Permission perm1 = new PropertyPermission("java.class.path",
+                "read");
+        final Permission perm2 = new PropertyPermission("java.path", "write");
+
+        PermissionCollection col1 = perm1.newPermissionCollection();
+        col1.add(perm1);
+        final ProtectionDomain pd1 = new ProtectionDomain(null, col1);
+        AccessControlContext acc1 = new AccessControlContext(
+                new ProtectionDomain[] { pd1 });
+
+        AccessControlContext acc2 = new AccessControlContext(
+                new ProtectionDomain[] { pd1 });
+
+        PermissionCollection col2 = perm2.newPermissionCollection();
+        col2.add(perm2);
+        col2.add(perm2);
+        final ProtectionDomain pd2 = new ProtectionDomain(null, col2);
+        AccessControlContext acc3 = new AccessControlContext(
+                new ProtectionDomain[] { pd2 });
+
+        assertTrue(acc1.hashCode() == acc1.hashCode());
+        assertTrue(acc2.hashCode() == acc2.hashCode());
+        assertTrue(acc3.hashCode() == acc3.hashCode());
+
+        assertTrue(acc1.hashCode() == acc2.hashCode());
+        assertTrue(acc2.hashCode() != acc3.hashCode());
+        assertTrue(acc3.hashCode() != acc1.hashCode());
+
+        AccessControlContext context = AccessController.getContext();
+
+        AccessControlContext acc4 = new AccessControlContext(context, null);
+        AccessControlContext acc5 = new AccessControlContext(context,
+                new SubjectDomainCombiner(new Subject()));
+
+        AccessControlContext acc6 = new AccessControlContext(context, null);
+
+        assertTrue(acc4.hashCode() == acc4.hashCode());
+        assertTrue(acc5.hashCode() == acc5.hashCode());
+        assertTrue(acc6.hashCode() == acc6.hashCode());
+
+        assertTrue(acc4.hashCode() == acc5.hashCode());
+        assertTrue(acc5.hashCode() == acc6.hashCode());
+        assertTrue(acc6.hashCode() == acc4.hashCode());
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/tests/api/java/security/AllTests.java b/libcore/security/src/test/java/tests/api/java/security/AllTests.java
new file mode 100644
index 0000000..4e846eb
--- /dev/null
+++ b/libcore/security/src/test/java/tests/api/java/security/AllTests.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.api.java.security;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * This is autogenerated source file. Includes tests for package tests.api.java.security;
+ */
+
+public class AllTests {
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(AllTests.suite());
+    }
+
+    public static Test suite() {
+        TestSuite suite = new TestSuite("All tests for package tests.api.java.security;");
+        // $JUnit-BEGIN$
+
+        suite.addTestSuite(AccessControlContextTest.class);
+        suite.addTestSuite(DomainCombinerTest.class);
+        suite.addTestSuite(PermissionCollectionTest.class);
+
+        // $JUnit-END$
+        return suite;
+    }
+}
diff --git a/libcore/security/src/test/java/tests/api/java/security/DomainCombinerTest.java b/libcore/security/src/test/java/tests/api/java/security/DomainCombinerTest.java
new file mode 100644
index 0000000..ac27b00
--- /dev/null
+++ b/libcore/security/src/test/java/tests/api/java/security/DomainCombinerTest.java
@@ -0,0 +1,121 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.api.java.security;
+
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.AllPermission;
+import java.security.BasicPermission;
+import java.security.CodeSource;
+import java.security.DomainCombiner;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+import java.security.SecurityPermission;
+import java.security.cert.Certificate;
+
+public class DomainCombinerTest extends junit.framework.TestCase {
+
+    /**
+     * @tests java.security.DomainCombiner#combine(java.security.ProtectionDomain[],
+     *        java.security.ProtectionDomain[])
+     */
+    public void test_combine$Ljava_security_ProtectionDomain$Ljava_security_ProtectionDomain() {
+        final boolean[] calledDomainCombiner = new boolean[] { false, false };
+
+        class MyCombiner implements DomainCombiner {
+            int i;
+
+            MyCombiner(int i) {
+                this.i = i;
+            }
+
+            public ProtectionDomain[] combine(
+                    ProtectionDomain[] executionDomains,
+                    ProtectionDomain[] parentDomains) {
+                calledDomainCombiner[i] = true;
+                PermissionCollection pc = new Permissions();
+                pc.add(new AllPermission());
+                ProtectionDomain pd;
+                // if run with the system classloader then there will be no
+                // execution domains 
+                if (executionDomains.length > 0) {
+                    pd = new ProtectionDomain(executionDomains[0]
+                            .getCodeSource(), pc);
+                } else {
+                    pd = new ProtectionDomain(parentDomains[0].getCodeSource(),
+                            pc);
+                }
+                return new ProtectionDomain[] { pd };
+            }
+        }
+
+        ProtectionDomain[] domains = new ProtectionDomain[] { new ProtectionDomain(
+                new CodeSource(null, (Certificate[]) null), new Permissions()) };
+
+        AccessControlContext parent = new AccessControlContext(domains);
+        AccessControlContext c0 = new AccessControlContext(parent,
+                new MyCombiner(0));
+        final AccessControlContext c1 = new AccessControlContext(parent,
+                new MyCombiner(1));
+
+                class TestPermission extends BasicPermission {
+                    TestPermission(String s) {
+                        super(s);
+                    }
+                }
+        
+        SecurityManager sm = new SecurityManager() {
+            public void checkPermission(Permission p) {
+                if( p instanceof TestPermission ) {
+                    super.checkPermission(p);   
+                }
+            }
+        };
+        sm.checkPermission(new SecurityPermission("let it load"));
+        
+        System.setSecurityManager(sm);
+        try {
+            AccessController.doPrivileged(new PrivilegedAction<Object>() {
+                public Object run() {
+                    // AccessController.getContext();
+                    AccessController.checkPermission(new TestPermission(
+                            "MyTest"));
+
+                    AccessController.doPrivileged(new PrivilegedAction<Object>() {
+                        public Object run() {
+                            AccessController
+                                    .checkPermission(new TestPermission(
+                                            "MyTest"));
+                            return null;
+                        }
+                    }, c1);
+                    return null;
+                }
+            }, c0);
+            assertTrue("Failed to combine domains for security permission",
+                    calledDomainCombiner[0]);
+            assertTrue("Failed to combine domains for security permission",
+                    calledDomainCombiner[1]);
+        } finally {
+            System.setSecurityManager(null);
+        }
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/tests/api/java/security/PermissionCollectionTest.java b/libcore/security/src/test/java/tests/api/java/security/PermissionCollectionTest.java
new file mode 100644
index 0000000..70a614b
--- /dev/null
+++ b/libcore/security/src/test/java/tests/api/java/security/PermissionCollectionTest.java
@@ -0,0 +1,239 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.api.java.security;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.PermissionCollection;
+import java.security.SecurityPermission;
+import java.util.StringTokenizer;
+
+import tests.support.Support_Exec;
+import tests.support.Support_GetLocal;
+import tests.support.resource.Support_Resources;
+
+public class PermissionCollectionTest extends junit.framework.TestCase {
+
+    // The below test is known to fail. Haven't got to the bottom of
+    // it yet but here is what has been determined :-
+    //
+    // * the Support_PermissionCollection application that is forked off
+    // near the end of this test needs to verify a signed jar (signedBKS.jar).
+    // This means that com.ibm.oti.util.JarUtils.verifySignature() ends up
+    // getting called. But at present that exists as just a lightweight/stub
+    // implementation which simply returns NULL. That behaviour causes a
+    // security exception inside java.util.jar.JarVerifier.
+    //
+    // * the above problem was fixed by rebuilding Harmony with the STUB
+    // IMPLEMENTATION of com.ibm.oti.util.JarUtils.verifySignature() replaced
+    // with one that delegates to
+    // org.apache.harmony.security.utils.JarUtils.verifySignature().
+    //
+    // * unfortunately, a NPE is raised in line 103 of Harmony's JarUtils class.
+    //
+    // * the cause of that NPE has still not been determined. Could it be
+    // related to Harmony's current stub implementation of BigInteger ?
+    /**
+     * @tests java.security.PermissionCollection#implies(java.security.Permission)
+     */
+    public void test_impliesLjava_security_Permission() throws Exception{
+
+        // Look for the tests classpath
+        URL classURL = this.getClass().getProtectionDomain().getCodeSource()
+                .getLocation();
+        assertNotNull("Could not get this class' location", classURL);
+
+        File policyFile = Support_GetLocal.createTempFile(".policy");
+        policyFile.deleteOnExit();
+
+        URL signedBKS = getResourceURL("PermissionCollection/signedBKS.jar");
+        URL keystoreBKS = getResourceURL("PermissionCollection/keystore.bks");
+        
+        // Create the policy file (and save the existing one if any)
+        FileOutputStream fileOut = null;
+        try {
+            fileOut = new FileOutputStream(policyFile);
+            String linebreak = System.getProperty("line.separator");
+            StringBuilder towrite = new StringBuilder();
+            towrite.append("grant {");
+            towrite.append(linebreak);
+            towrite.append("permission java.io.FilePermission \"");
+            towrite.append(signedBKS.getFile());
+            towrite.append("\", \"read\";");
+            towrite.append(linebreak);
+            towrite.append("permission java.lang.RuntimePermission \"getProtectionDomain\";");
+            towrite.append(linebreak);
+            towrite.append("permission java.security.SecurityPermission \"getPolicy\";");
+            towrite.append(linebreak);
+            towrite.append("};");
+            towrite.append(linebreak);
+            towrite.append("grant codeBase \"");
+            towrite.append(signedBKS.toExternalForm());
+            towrite.append("\" signedBy \"eleanor\" {");
+            towrite.append(linebreak);
+            towrite.append("permission java.io.FilePermission \"test1.txt\", \"write\";");
+            towrite.append(linebreak);
+            towrite.append("permission mypackage.MyPermission \"essai\", signedBy \"eleanor,dylan\";");
+            towrite.append(linebreak);
+            towrite.append("};");
+            towrite.append(linebreak);
+            towrite.append("grant codeBase \"");
+            towrite.append(signedBKS.toExternalForm());
+            towrite.append("\" signedBy \"eleanor\" {");
+            towrite.append(linebreak);
+            towrite.append("permission java.io.FilePermission \"test2.txt\", \"write\";");
+            towrite.append(linebreak);
+            towrite.append("};");
+            towrite.append(linebreak);
+            towrite.append("grant codeBase \"");
+            towrite.append(classURL.toExternalForm());
+            towrite.append("\" {");
+            towrite.append(linebreak);
+            towrite.append("permission java.security.AllPermission;");
+            towrite.append(linebreak);
+            towrite.append("};");
+            towrite.append(linebreak);
+            towrite.append("keystore \"");
+            towrite.append(keystoreBKS.toExternalForm());
+            towrite.append("\",\"BKS\";");            
+            fileOut.write(towrite.toString().getBytes());
+            fileOut.flush();
+        } finally {
+            if (fileOut != null) {
+                fileOut.close();
+            }
+        }
+
+        // Copy mypermissionBKS.jar to the user directory so that it can be put
+        // in
+        // the classpath
+        File jarFile = null;
+        FileOutputStream fout = null;
+        InputStream jis = null;
+        try {
+            jis = Support_Resources
+                    .getResourceStream("PermissionCollection/mypermissionBKS.jar");
+            jarFile = Support_GetLocal.createTempFile(".jar");
+            jarFile.deleteOnExit();
+            fout = new FileOutputStream(jarFile);
+            int c = jis.read();
+            while (c != -1) {
+                fout.write(c);
+                c = jis.read();
+            }
+            fout.flush();
+        } finally {
+            if (fout != null) {
+                fout.close();
+            }
+            if (jis != null) {
+                jis.close();
+            }
+        }
+
+        String classPath = new File(classURL.getFile()).getPath();
+
+        // Execute Support_PermissionCollection in another VM
+        String[] classPathArray = new String[2];
+        classPathArray[0] = classPath;
+        classPathArray[1] = jarFile.getPath();
+        String[] args = { "-Djava.security.policy=" + policyFile.toURL(),
+                "tests.support.Support_PermissionCollection",
+                signedBKS.toExternalForm() };
+
+        String result = Support_Exec.execJava(args, classPathArray, true);
+
+        StringTokenizer resultTokenizer = new StringTokenizer(result, ",");
+
+        // Check the test result from the new VM process
+        assertEquals("Permission should be granted", "false", resultTokenizer
+                .nextToken());
+        assertEquals("signed Permission should be granted", "false",
+                resultTokenizer.nextToken());
+        assertEquals("Permission should not be granted", "false",
+                resultTokenizer.nextToken());
+    }
+
+    /**
+     * @tests java.security.PermissionCollection#PermissionCollection()
+     */
+    public void test_Constructor() {
+        // test java.security.permissionCollection.PermissionCollection()
+        SecurityPermission permi = new SecurityPermission(
+                "testing permissionCollection-isReadOnly");
+        PermissionCollection permCollect = permi.newPermissionCollection();
+        assertNotNull("creat permissionCollection constructor returned a null",
+                permCollect);
+    }
+
+    /**
+     * @tests java.security.PermissionCollection#isReadOnly()
+     */
+    public void test_isReadOnly() {
+        // test java.security.permissionCollection.isReadOnly()
+        SecurityPermission permi = new SecurityPermission(
+                "testing permissionCollection-isREadOnly");
+        PermissionCollection permCollect = permi.newPermissionCollection();
+        assertTrue("readOnly has not been set, but isReadOnly returned true",
+                !permCollect.isReadOnly());
+        permCollect.setReadOnly();
+        assertTrue("readOnly is set, but isReadonly returned false",
+                permCollect.isReadOnly());
+    }
+
+    /**
+     * @tests java.security.PermissionCollection#setReadOnly()
+     */
+    public void test_setReadOnly() {
+        // test java.security.permissionCollection.setReadOnly()
+        SecurityPermission permi = new SecurityPermission(
+                "testing permissionCollection-setReadOnly");
+        PermissionCollection permCollect = permi.newPermissionCollection();
+        assertTrue("readOnly has not been set, but isReadOnly returned true",
+                !permCollect.isReadOnly());
+        permCollect.setReadOnly();
+        assertTrue("readOnly is set, but isReadonly returned false",
+                permCollect.isReadOnly());
+    }
+
+    /**
+     * @tests java.security.PermissionCollection#toString()
+     */
+    public void test_toString() {
+        // test java.security.permissionCollection.toString()
+        SecurityPermission permi = new SecurityPermission(
+                "testing permissionCollection-isREadOnly");
+        assertNotNull("toString should have returned a string of elements",
+                permi.newPermissionCollection().toString());
+        assertTrue(permi.newPermissionCollection().toString().endsWith("\n"));
+    }
+
+    // FIXME move me to Support_Resources
+    public static URL getResourceURL(String name) {
+
+        URL url = ClassLoader.getSystemClassLoader().getResource(name);
+
+        if (url == null) {
+            throw new RuntimeException("Failed to get resource url: " + name);
+        }
+
+        return url;
+    }
+}
\ No newline at end of file
diff --git a/libcore/security/src/test/java/tests/java/security/AlgorithmParameterGeneratorSpiTest.java b/libcore/security/src/test/java/tests/java/security/AlgorithmParameterGeneratorSpiTest.java
new file mode 100644
index 0000000..161183c
--- /dev/null
+++ b/libcore/security/src/test/java/tests/java/security/AlgorithmParameterGeneratorSpiTest.java
@@ -0,0 +1,83 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Vera Y. Petrashkova
+ * @version $Revision$
+ */
+
+package tests.java.security;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.apache.harmony.security.tests.support.MyAlgorithmParameterGeneratorSpi;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>AlgorithmParameterGeneratorSpi</code> class constructors
+ * and methods.
+ * 
+ */
+
+public class AlgorithmParameterGeneratorSpiTest extends TestCase {
+
+    /**
+     * Constructor for CertPathBuilderTests.
+     * 
+     * @param name
+     */
+    public AlgorithmParameterGeneratorSpiTest(String name) {
+        super(name);
+    }
+
+    /**
+     * Test for <code>AlgorithmParameterGeneratorSpi</code> constructor
+     * Assertion: constructs AlgorithmParameterGeneratorSpi
+     */
+    public void testAlgorithmParameterGeneratorSpi01()
+            throws InvalidAlgorithmParameterException {
+        MyAlgorithmParameterGeneratorSpi algParGen = new MyAlgorithmParameterGeneratorSpi();
+        AlgorithmParameters param = algParGen.engineGenerateParameters();
+        assertNull("Not null parameters", param);
+        AlgorithmParameterSpec pp = null;
+        algParGen.engineInit(pp, new SecureRandom());
+        try {
+            algParGen.engineInit(pp, null);
+            fail("IllegalArgumentException must be thrown");
+        } catch (IllegalArgumentException e) {
+        }
+        algParGen.engineInit(0, null);
+        algParGen.engineInit(0, new SecureRandom());
+
+        try {
+            algParGen.engineInit(-10, null);
+            fail("IllegalArgumentException must be thrown");
+        } catch (IllegalArgumentException e) {
+        }
+        try {
+            algParGen.engineInit(-10, new SecureRandom());
+            fail("IllegalArgumentException must be thrown");
+        } catch (IllegalArgumentException e) {
+        }
+    }
+
+    
+}
diff --git a/libcore/security/src/test/java/tests/java/security/AllPermissionTest.java b/libcore/security/src/test/java/tests/java/security/AllPermissionTest.java
new file mode 100644
index 0000000..0d2d738
--- /dev/null
+++ b/libcore/security/src/test/java/tests/java/security/AllPermissionTest.java
@@ -0,0 +1,97 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package tests.java.security;
+
+import java.security.AllPermission;
+import java.security.BasicPermission;
+import java.security.PermissionCollection;
+import java.security.UnresolvedPermission;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>AllPermission</code>
+ * 
+ */
+public class AllPermissionTest extends TestCase {
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(AllPermissionTest.class);
+    }
+
+    /**
+     * Constructor for AllPermissionsTest.
+     * @param arg0
+     */
+    public AllPermissionTest(String arg0) {
+        super(arg0);
+    }
+    
+    /**
+     * Test all constructors: an object is created, name and actions are ignored
+     */
+    public void testCtor()
+    {
+        AllPermission a1 = new AllPermission();
+        assertEquals("<all permissions>", a1.getName());
+        assertEquals("<all actions>", a1.getActions());
+        
+        a1 = new AllPermission("sdfsdfwe&^$", "*&IUGJKHVB764");
+        assertEquals("<all permissions>", a1.getName());
+        assertEquals("<all actions>", a1.getActions());
+        
+        a1 = new AllPermission(null, "");
+        assertEquals("<all permissions>", a1.getName());
+        assertEquals("<all actions>", a1.getActions());
+    }
+
+    /** Any of AllPermission instances are equal and have the same hash code */
+    public void testEquals()
+    {
+        AllPermission a1 = new AllPermission();
+        AllPermission a2 = new AllPermission();
+        assertTrue(a1.equals(a2));
+        assertTrue(a1.hashCode() == a2.hashCode());
+        assertFalse(a1.equals(null));
+        assertFalse(a1.equals(new BasicPermission("hgf"){}));
+    }
+    
+    /** AllPermission implies any other permission */
+    public void testImplies()
+    {
+        AllPermission a1 = new AllPermission();
+        assertTrue(a1.implies(new AllPermission()));
+        assertTrue(a1.implies(new BasicPermission("2323"){}));
+        assertTrue(a1.implies(new UnresolvedPermission("2323", "", "", null)));
+    }
+    
+    /** newPermissionCollection() returns a new AllPermissionCollection on every invocation. */
+    public void testCollection()
+    {
+        AllPermission a1 = new AllPermission();
+        PermissionCollection pc1 = a1.newPermissionCollection();
+        PermissionCollection pc2 = a1.newPermissionCollection();
+//        assertTrue((pc1 instanceof AllPermissionCollection) && (pc2 instanceof AllPermissionCollection));
+        assertNotSame(pc1, pc2);
+    }
+}
diff --git a/libcore/security/src/test/java/tests/java/security/AllTests.java b/libcore/security/src/test/java/tests/java/security/AllTests.java
new file mode 100644
index 0000000..23e2eb2
--- /dev/null
+++ b/libcore/security/src/test/java/tests/java/security/AllTests.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.java.security;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * This is autogenerated source file. Includes tests for package tests.java.security;
+ */
+
+public class AllTests {
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(AllTests.suite());
+    }
+
+    public static Test suite() {
+        TestSuite suite = new TestSuite("All tests for package tests.java.security;");
+        // $JUnit-BEGIN$
+
+        suite.addTestSuite(AlgorithmParameterGeneratorSpiTest.class);
+        suite.addTestSuite(AllPermissionTest.class);
+        suite.addTestSuite(BasicPermissionTest.class);
+        suite.addTestSuite(IdentityTest.class);
+        suite.addTestSuite(ProviderTest.class);
+        suite.addTestSuite(SecureClassLoaderTest.class);
+        suite.addTestSuite(SecureRandomTest.class);
+        suite.addTestSuite(SignatureTest.class);
+
+        // $JUnit-END$
+        return suite;
+    }
+}
diff --git a/libcore/security/src/test/java/tests/java/security/BasicPermissionTest.java b/libcore/security/src/test/java/tests/java/security/BasicPermissionTest.java
new file mode 100644
index 0000000..c0485fe
--- /dev/null
+++ b/libcore/security/src/test/java/tests/java/security/BasicPermissionTest.java
@@ -0,0 +1,145 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Alexey V. Varlamov
+* @version $Revision$
+*/
+
+package tests.java.security;
+
+import java.security.BasicPermission;
+import java.security.PermissionCollection;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>BasicPermission</code>
+ * 
+ */
+
+public class BasicPermissionTest extends TestCase {
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(BasicPermissionTest.class);
+    }
+
+    /**
+     * Constructor for BasicPermissionTest.
+     * @param arg0
+     */
+    public BasicPermissionTest(String arg0) {
+        super(arg0);
+    }
+
+    /**
+     * Check all constructors: an object is created with the specified valid name. 
+     * If name equal null then NPE should be thrown. 
+     * If  name is empty then IAE should be thrown. 
+     * Action is ignored.
+     */
+    public void testCtor()
+    {
+        String name = "basic123*$%#";
+        BasicPermission test = new BasicPermission(name){};
+        assertEquals(name, test.getName());
+        assertEquals("", test.getActions());
+        test = new BasicPermission(name, "#$!#12435"){};
+        assertEquals(name, test.getName());
+        assertEquals("", test.getActions());
+        try{
+            new BasicPermission(null){};
+            fail("NPE is not thrown");
+        }
+        catch (NullPointerException ok){}
+        
+        try{
+            new BasicPermission(null, "ds235"){};
+            fail("NPE is not thrown");
+        }
+        catch (NullPointerException ok){}
+        
+        try{
+            new BasicPermission(""){};
+            fail("IAE is not thrown");
+        }
+        catch (IllegalArgumentException ok){}
+        try{
+            new BasicPermission("", "ertre 3454"){};
+            fail("IAE is not thrown");
+        }
+        catch (IllegalArgumentException ok){}
+    }
+    
+    private final class BasicPermissionImpl extends BasicPermission
+    {
+        public BasicPermissionImpl(String name)
+        {
+            super(name);
+        }
+    }
+    
+    /**
+     * two BasicPermissions are equal if name and class are equal; 
+     * equal permissions should have the same hash code
+     */
+    public void testEquals()
+    {
+        BasicPermission b1 = new BasicPermissionImpl("abc");
+        BasicPermission b2 = null;
+        assertTrue(b1.equals(b1)); 
+        assertFalse(b1.equals(null));
+        assertFalse(b1.equals(new Object()));
+        assertFalse(b1.equals("abc"));
+        assertTrue(b1.equals(b2 = new BasicPermissionImpl("abc")));
+        assertTrue(b1.hashCode() == b2.hashCode());
+        assertFalse(b1.equals(new BasicPermission("abc"){}));
+        assertFalse(b1.equals(new BasicPermissionImpl("abc.*")));
+    }
+
+    /** 
+     * implies() should return true if a permission is equal to or is implied 
+     * by wildcarded permission, false otherwise.
+     */
+    public void testImplies()
+    {
+        BasicPermission b1 = new BasicPermissionImpl("a.b.c");
+        assertTrue(b1.implies(b1));
+        assertTrue(b1.implies(new BasicPermissionImpl("a.b.c")));
+        assertFalse(b1.implies(new BasicPermissionImpl("a.b.c.*")));
+        assertFalse(b1.implies(new BasicPermission("a.b.c"){}));
+        assertTrue(new BasicPermissionImpl("a.b.*").implies(b1));
+        assertTrue(new BasicPermissionImpl("a.*").implies(b1));
+        assertTrue(new BasicPermissionImpl("*").implies(b1));
+        assertFalse(new BasicPermissionImpl("a.b*").implies(b1));
+        assertFalse(new BasicPermissionImpl("a.b.c.*").implies(b1));
+        assertTrue(new BasicPermissionImpl("1.*").implies(new BasicPermissionImpl("1.234.*")));
+        assertTrue(new BasicPermissionImpl("*").implies(new BasicPermissionImpl("*")));
+    }
+    
+    /**
+     * newPermissionCollection() should return new BasicPermissionCollection on every invocation
+     */
+    public void testCollection()
+    {
+        BasicPermission b1 = new BasicPermissionImpl("a.b.c");
+        PermissionCollection pc1 = b1.newPermissionCollection();
+        PermissionCollection pc2 = b1.newPermissionCollection();
+//        assertTrue((pc1 instanceof BasicPermissionCollection) && (pc2 instanceof BasicPermissionCollection));
+        assertNotSame(pc1, pc2);
+    }
+}
diff --git a/libcore/security/src/test/java/tests/java/security/IdentityTest.java b/libcore/security/src/test/java/tests/java/security/IdentityTest.java
new file mode 100644
index 0000000..8854c48
--- /dev/null
+++ b/libcore/security/src/test/java/tests/java/security/IdentityTest.java
@@ -0,0 +1,435 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Aleksei Y. Semenov
+* @version $Revision$
+*/
+
+package tests.java.security;
+
+
+import java.security.Identity;
+import java.security.IdentityScope;
+import java.security.KeyManagementException;
+import java.security.Permission;
+import java.security.Permissions;
+import java.security.PublicKey;
+import java.security.SecurityPermission;
+
+import org.apache.harmony.security.tests.support.CertificateStub;
+import org.apache.harmony.security.tests.support.IdentityStub;
+import org.apache.harmony.security.tests.support.PublicKeyStub;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for class Identity
+ * 
+ */
+@SuppressWarnings("deprecation")
+public class IdentityTest extends TestCase {
+
+    public static class MySecurityManager extends SecurityManager {
+        public Permissions denied = new Permissions(); 
+        public void checkPermission(Permission permission){
+            if (denied!=null && denied.implies(permission)) throw new SecurityException();
+        }
+    }
+    
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(IdentityTest.class);
+    }
+
+    /**
+     * Constructor for IdentityTest.
+     * @param name
+     */
+    public IdentityTest(String name) {
+        super(name);
+    }
+    
+    public void testHashCode() {
+        new IdentityStub("testHashCode").hashCode();
+    }
+
+    public void testEquals() throws Exception {
+        IdentityStub i1 = new IdentityStub("testEquals");
+        Object value[] =  {
+                null, Boolean.FALSE,
+                new Object(), Boolean.FALSE,
+                i1, Boolean.TRUE,
+                new IdentityStub(i1.getName()), Boolean.TRUE
+        };
+        
+        for (int k=0; k<value.length; k+=2) {
+            assertEquals(value[k+1], new Boolean(i1.equals(value[k])));
+            if (Boolean.TRUE.equals(value[k+1])) assertEquals(i1.hashCode(), value[k].hashCode());
+        }
+        // check other cases
+        Identity i2 = new IdentityStub("testEquals", IdentityScope.getSystemScope());
+        assertEquals(i1.identityEquals(i2), i1.equals(i2));
+        Identity i3 = new IdentityStub("testEquals3");
+        assertEquals(i1.identityEquals(i3), i1.equals(i3));
+        
+    }
+
+    /**
+     * verify Identity.toString() throws Exception is permission is denied
+     */
+    public void testToString1() {
+        MySecurityManager sm = new MySecurityManager();
+        sm.denied.add(new SecurityPermission("printIdentity"));
+        System.setSecurityManager(sm);
+        try {
+            new IdentityStub("testToString").toString();
+            fail("SecurityException should be thrown");
+        } catch (SecurityException ok) {
+        } finally {
+            System.setSecurityManager(null);
+        }          
+    }
+    /**
+     * verify Identity.toString() 
+     */
+     public void testToString2() {    
+        assertNotNull(new IdentityStub("testToString2").toString());
+    }
+
+    /**
+     * verify Identity() creates instance
+     */
+    public void testIdentity() {
+        assertNotNull(new IdentityStub());
+    }
+
+    /*
+     * verify Identity(String) creates instance with given name
+     */
+    public void testIdentityString() {
+        Identity i = new IdentityStub("iii");
+        assertNotNull(i);
+        assertEquals("iii", i.getName());
+        i=new IdentityStub(null);
+        assertNotNull(i);
+        assertNull(i.getName());
+    }
+
+    /**
+     * verify Identity(String, IdentityScope) creates instance with given name and in give scope
+     */
+    public void testIdentityStringIdentityScope() throws Exception {
+        IdentityScope s = IdentityScope.getSystemScope();        
+        Identity i = new IdentityStub("iii2", s);
+        assertNotNull(i);
+        assertEquals("iii2", i.getName());
+        assertSame(s, i.getScope());
+        assertSame(i, s.getIdentity(i.getName()));        
+    }
+
+    /**
+     * verify addCertificate(Certificate certificate) adds a certificate for this identity.
+     * If the identity has a public key, the public key in the certificate must be the same
+     *  
+     */
+    public void testAddCertificate1() throws Exception {
+        Identity i = new IdentityStub("iii");
+        PublicKeyStub pk1 = new PublicKeyStub("kkk", "fff", new byte[]{1,2,3,4,5});
+        i.setPublicKey(pk1);
+        // try with the same key
+        CertificateStub c1 = new CertificateStub("fff", null, null, pk1);
+        i.addCertificate(c1);
+        assertSame(c1, i.certificates()[0]);
+        // try Certificate with different key
+        try {
+            i.addCertificate(new CertificateStub("ccc", null, null, new PublicKeyStub("k2", "fff", new byte[]{6,7,8,9,0})));
+            fail("KeyManagementException should be thrown");
+        } catch (KeyManagementException ok) {}        
+    }
+
+    /**
+     * verify addCertificate(Certificate certificate) adds a certificate for this identity.
+     * if the identity does not have a public key, the identity's public key is set to be that specified in the certificate.
+     */
+
+    public void testAddCertificate2() throws Exception {
+        Identity i = new IdentityStub("iii");
+        PublicKeyStub pk1 = new PublicKeyStub("kkk", "fff", null);        
+        CertificateStub c1 = new CertificateStub("fff", null, null, pk1);
+        i.addCertificate(c1);
+        assertSame(c1, i.certificates()[0]);
+        assertSame(pk1, i.getPublicKey());
+            
+    }
+    
+    /**
+     * verify addCertificate(Certificate certificate) throws SecurityException is permission is denied
+     */
+
+    public void testAddCertificate3() throws Exception {
+        MySecurityManager sm = new MySecurityManager();
+        sm.denied.add(new SecurityPermission("addIdentityCertificate"));
+        System.setSecurityManager(sm);
+        try {
+            new IdentityStub("iii").addCertificate(new CertificateStub("ccc", null, null, null));
+            fail("SecurityException should be thrown");
+        } catch (SecurityException ok) {
+        } finally {
+            System.setSecurityManager(null);
+        }        
+    }
+    
+    /**
+     * verify addCertificate(Certificate certificate) throws KeyManagementException if certificate is null
+     */
+    public void testAddCertificate4() throws Exception {
+        try {
+            new IdentityStub("aaa").addCertificate(null);
+            fail("KeyManagementException should be thrown");
+        } catch (KeyManagementException ok) {
+        } catch (NullPointerException ok) {}
+        
+    }
+//
+//  Commented out since there will no be fix for the test failure    
+//    /**
+//     * verify removeCertificate(Certificate certificate) removes certificate
+//     */
+//    public void testRemoveCertificate1() throws Exception{
+//        Identity i = new IdentityStub("iii");
+//        PublicKeyStub pk1 = new PublicKeyStub("kkk", "fff", null);        
+//        CertificateStub c1 = new CertificateStub("fff", null, null, pk1);
+//        i.addCertificate(c1);
+//        assertSame(c1, i.certificates()[0]);
+//        i.removeCertificate(c1);
+//        assertEquals(0, i.certificates().length);
+//        // throw KeyManagementException if certificate not found
+//        try {
+//            i.removeCertificate(c1);
+//            fail("KeyManagementException should be thrown");
+//        } catch (KeyManagementException ok) {     
+//        }
+//        try {
+//            i.removeCertificate(null);
+//            fail("KeyManagementException should be thrown");
+//        } catch (KeyManagementException ok) {
+//            
+//        }
+//    }
+    /**
+     * verify removeCertificate(Certificate certificate) throws SecurityException if permission is denied
+     */ 
+    public void testRemoveCertificate2() throws Exception{
+        MySecurityManager sm = new MySecurityManager();
+        sm.denied.add(new SecurityPermission("removeIdentityCertificate"));
+        Identity i = new IdentityStub("iii");
+        i.addCertificate(new CertificateStub("ccc", null, null, null));
+        System.setSecurityManager(sm);
+        try {
+            i.removeCertificate(i.certificates()[0]);
+            fail("SecurityException should be thrown");
+        } catch (SecurityException ok) {
+        } finally {
+            System.setSecurityManager(null);
+        }
+        
+    }
+
+    /**
+     * verify certificates() returns a copy of all certificates for this identity
+     */
+    public void testCertificates() throws Exception {
+        Identity i = new IdentityStub("iii");
+        PublicKeyStub pk1 = new PublicKeyStub("kkk", "fff", null);        
+        CertificateStub c1 = new CertificateStub("fff", null, null, pk1);
+        CertificateStub c2 = new CertificateStub("zzz", null, null, pk1);
+        i.addCertificate(c1);
+        i.addCertificate(c2);
+        java.security.Certificate[] s = i.certificates();
+        assertEquals(2, s.length);
+        assertTrue(c1.equals(s[0]) || c2.equals(s[0]));
+        assertTrue(c1.equals(s[1]) || c2.equals(s[1]));
+        s[0] = null;
+        s[1] = null;
+        // check that the copy was modified
+        s = i.certificates();
+        assertEquals(2, s.length);
+        assertTrue(c1.equals(s[0]) || c2.equals(s[0]));
+        assertTrue(c1.equals(s[1]) || c2.equals(s[1]));
+    }
+
+    /**
+     * verify Identity.identityEquals(Identity) return true, only if names and public keys are equal 
+     */
+    public void testIdentityEquals() throws Exception {
+        String name = "nnn";
+        PublicKey pk = new PublicKeyStub("aaa", "fff", new byte[]{1,2,3,4,5});
+        IdentityStub i = new IdentityStub(name);
+        i.setPublicKey(pk);
+        Object[] value = {
+                //null, Boolean.FALSE,
+                //new Object(), Boolean.FALSE,
+                new IdentityStub("111"), Boolean.FALSE,
+                new IdentityStub(name), Boolean.FALSE,
+                new IdentityStub(name, IdentityScope.getSystemScope()), Boolean.FALSE,
+                i, Boolean.TRUE,
+                new IdentityStub(name, pk), Boolean.TRUE                
+        };
+        for (int k=0; k<value.length; k+=2){
+            assertEquals(value[k+1], new Boolean(i.identityEquals((Identity)value[k])));
+            if (Boolean.TRUE.equals(value[k+1])) assertEquals(i.hashCode(), value[k].hashCode());
+        }
+        Identity i2 = IdentityScope.getSystemScope().getIdentity(name); 
+        i2.setPublicKey(pk);        
+        assertTrue(i.identityEquals(i2));
+    }
+
+    /**
+     * verify Identity.toString(boolean) return string representation of identity
+     */
+    public void testToStringboolean() throws Exception {
+        new IdentityStub("aaa").toString(false);
+        new IdentityStub("aaa2", IdentityScope.getSystemScope()).toString(false);
+        new IdentityStub("bbb").toString(true);
+        new IdentityStub("bbb2", IdentityScope.getSystemScope()).toString(true);
+    }
+
+    /**
+     * verify Identity.getScope() returns identity's scope
+     */ 
+    public void testGetScope() throws Exception {
+       Identity i = new IdentityStub("testGetScope");
+       assertNull(i.getScope());
+       IdentityScope s = IdentityScope.getSystemScope();
+       
+       Identity i2 = new IdentityStub("testGetScope2", s);
+       assertSame(s, i2.getScope());
+        
+    }
+    /**
+     * 
+     * verify Identity.setPublicKey() throws SecurityException if permission is denied
+     *
+     */
+    public void testSetPublicKey1() throws Exception {
+        MySecurityManager sm = new MySecurityManager();
+        sm.denied.add(new SecurityPermission("setIdentityPublicKey"));
+        System.setSecurityManager(sm);
+        try {
+            new IdentityStub("testSetPublicKey1").setPublicKey(new PublicKeyStub("kkk", "testSetPublicKey1", null));
+            fail("SecurityException should be thrown");
+        } catch (SecurityException ok) {
+        } finally {
+            System.setSecurityManager(null);
+        }        
+    
+    }
+    /**
+     * 
+     * verify Identity.setPublicKey() throws KeyManagementException if key is invalid 
+     *
+     */
+    public void testSetPublicKey2() throws Exception {
+        Identity i2 = new IdentityStub("testSetPublicKey2_2", IdentityScope.getSystemScope());
+        new PublicKeyStub("kkk", "testSetPublicKey2", new byte[]{1,2,3,4,5});
+        try {
+            i2.setPublicKey(null);
+            //fail("KeyManagementException should be thrown - key is null");            
+        } catch (KeyManagementException ok) {}
+    }
+    
+//
+//  Commented out since there will no be fix for the test failure       
+//    /**
+//     * 
+//     * verify Identity.setPublicKey() throws KeyManagementException if key is already used 
+//     *
+//     */
+//    public void testSetPublicKey3() throws Exception {
+//        Identity i1 = new IdentityStub("testSetPublicKey3_1", IdentityScope.getSystemScope());
+//        Identity i2 = new IdentityStub("testSetPublicKey3_2", IdentityScope.getSystemScope());
+//        PublicKey pk = new PublicKeyStub("kkk", "fff", new byte[]{1,2,3,4,5});
+//        i1.setPublicKey(pk);
+//        try {
+//            i2.setPublicKey(pk);
+//            fail("KeyManagementException should be thrown - key already used");            
+//        } catch (KeyManagementException ok) {};
+//    }
+    /**
+     * 
+     * verify Identity.setPublicKey()  removes old key and all identity's certificates
+     *
+     */
+    public void testSetPublicKey4() throws Exception {
+        Identity i = new IdentityStub("testSetPublicKey4");
+        PublicKeyStub pk1 = new PublicKeyStub("kkk", "Identity.testSetPublicKey4", null);        
+        CertificateStub c1 = new CertificateStub("fff", null, null, pk1);
+        CertificateStub c2 = new CertificateStub("zzz", null, null, pk1);
+        i.addCertificate(c1);
+        i.addCertificate(c2);
+        assertEquals(2, i.certificates().length);
+        assertSame(pk1, i.getPublicKey());
+        
+        PublicKeyStub pk2 = new PublicKeyStub("zzz", "Identity.testSetPublicKey4", null);    
+        i.setPublicKey(pk2);
+        assertSame(pk2, i.getPublicKey());
+        assertEquals(0, i.certificates().length);
+    }
+    
+    /**
+     * verify Identity.getPublicKey() returns public key
+     */
+    public void testGetPublicKey() throws Exception {
+        Identity i = new IdentityStub("testGetPublicKey");
+        assertNull(i.getPublicKey());
+        PublicKey pk = new PublicKeyStub("kkk", "Identity.testGetPublicKey", null);
+        i.setPublicKey(pk);
+        assertSame(pk, i.getPublicKey());        
+    }
+
+    /**
+     * 
+     * verify Identity.setInfo() throws SecurityException if permission is denied
+     *
+     *
+     */
+    public void testSetInfo() throws Exception {
+        MySecurityManager sm = new MySecurityManager();
+        sm.denied.add(new SecurityPermission("setIdentityInfo"));
+        System.setSecurityManager(sm);
+        try {
+            new IdentityStub("testSetInfo").setInfo("some info");
+            fail("SecurityException should be thrown");
+        } catch (SecurityException ok) {
+        } finally {
+            System.setSecurityManager(null);
+        }        
+    }
+    
+    public void testGetInfo() {
+        
+        Identity i = new IdentityStub("testGetInfo");
+        i.setInfo("some info");
+        assertEquals("some info", i.getInfo());
+    }
+    
+    public void testGetName() {
+        Identity i = new IdentityStub("testGetName");
+        assertEquals ("testGetName", i.getName());
+    }
+
+}
diff --git a/libcore/security/src/test/java/tests/java/security/ProviderTest.java b/libcore/security/src/test/java/tests/java/security/ProviderTest.java
new file mode 100644
index 0000000..fb33d79
--- /dev/null
+++ b/libcore/security/src/test/java/tests/java/security/ProviderTest.java
@@ -0,0 +1,578 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Boris V. Kuznetsov
+ * @version $Revision$
+ */
+
+package tests.java.security;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.math.BigInteger;
+import java.security.*;
+import java.security.Provider.Service;
+import java.security.spec.RSAKeyGenParameterSpec;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>Provider</code> constructor and methods
+ * 
+ */
+public class ProviderTest extends TestCase {
+
+    Provider p;
+
+    /*
+     * @see TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+        super.setUp();
+        p = new MyProvider();
+    }
+
+    /*
+     * Class under test for void Provider()
+     */
+    public final void testProvider() {
+        if (!p.getProperty("Provider.id name").equals(
+                String.valueOf(p.getName()))) {
+            fail("Incorrect \"Provider.id name\" value");
+        }
+        if (!p.getProperty("Provider.id version").equals(
+                String.valueOf(p.getVersion()))) {
+            fail("Incorrect \"Provider.id version\" value");
+        }
+        if (!p.getProperty("Provider.id info").equals(
+                String.valueOf(p.getInfo()))) {
+            fail("Incorrect \"Provider.id info\" value");
+        }
+        if (!p.getProperty("Provider.id className").equals(
+                p.getClass().getName())) {
+            fail("Incorrect \"Provider.id className\" value");
+        }
+    }
+
+    public final void testClear() {
+        p.clear();
+        if (p.getProperty("MessageDigest.SHA-1") != null) {
+            fail("Provider contains properties");
+        }
+    }
+
+    /*
+     * Class under test for void Provider(String, double, String)
+     */
+    public final void testProviderStringdoubleString() {
+        Provider p = new MyProvider("Provider name", 123.456, "Provider info");
+        if (!p.getName().equals("Provider name") || p.getVersion() != 123.456
+                || !p.getInfo().equals("Provider info")) {
+            fail("Incorrect values");
+        }
+    }
+
+    public final void testGetName() {
+        if (!p.getName().equals("MyProvider")) {
+            fail("Incorrect provider name");
+        }
+    }
+
+    public final void testGetVersion() {
+        if (p.getVersion() != 1.0) {
+            fail("Incorrect provider version");
+        }
+    }
+
+    public final void testGetInfo() {
+        if (!p.getInfo().equals("Provider for testing")) {
+            fail("Incorrect provider info");
+        }
+    }
+
+    /*
+     * Class under test for void putAll(Map)
+     */
+    public final void testPutAllMap() {
+        HashMap<String, String> hm = new HashMap<String, String>();
+        hm.put("MessageDigest.SHA-1", "aaa.bbb.ccc.ddd");
+        hm.put("Property 1", "value 1");
+        hm.put("serviceName.algName attrName", "attrValue");
+        hm.put("Alg.Alias.engineClassName.aliasName", "stanbdardName");
+        p.putAll(hm);
+        if (!"value 1".equals(p.getProperty("Property 1").trim())
+                || !"attrValue".equals(p.getProperty(
+                        "serviceName.algName attrName").trim())
+                || !"stanbdardName".equals(p.getProperty(
+                        "Alg.Alias.engineClassName.aliasName").trim())
+                || !"aaa.bbb.ccc.ddd".equals(p.getProperty(
+                        "MessageDigest.SHA-1").trim())) {
+            fail("Incorrect property value");
+        }
+    }
+
+    /*
+     * Class under test for Set entrySet()
+     */
+    public final void testEntrySet() {
+        p.put("MessageDigest.SHA-256", "aaa.bbb.ccc.ddd");
+
+        Set s = p.entrySet();
+        try {
+            s.clear();
+            fail("Must return unmodifiable set");
+        } catch (UnsupportedOperationException e) {
+        }
+
+        assertEquals("Incorrect set size", 8, s.size());
+
+        for (Iterator it = s.iterator(); it.hasNext();) {
+            Entry e = (Entry) it.next();
+            String key = (String) e.getKey();
+            String val = (String) e.getValue();
+            if (key.equals("MessageDigest.SHA-1")
+                    && val.equals("SomeClassName")) {
+                continue;
+            }
+            if (key.equals("Alg.Alias.MessageDigest.SHA1")
+                    && val.equals("SHA-1")) {
+                continue;
+            }
+            if (key.equals("MessageDigest.abc") && val.equals("SomeClassName")) {
+                continue;
+            }
+            if (key.equals("Provider.id className")
+                    && val.equals(p.getClass().getName())) {
+                continue;
+            }
+            if (key.equals("Provider.id name") && val.equals("MyProvider")) {
+                continue;
+            }
+            if (key.equals("MessageDigest.SHA-256")
+                    && val.equals("aaa.bbb.ccc.ddd")) {
+                continue;
+            }
+            if (key.equals("Provider.id version") && val.equals("1.0")) {
+                continue;
+            }
+            if (key.equals("Provider.id info")
+                    && val.equals("Provider for testing")) {
+                continue;
+            }
+            fail("Incorrect set");
+        }
+    }
+
+    /*
+     * Class under test for Set keySet()
+     */
+    public final void testKeySet() {
+        p.put("MessageDigest.SHA-256", "aaa.bbb.ccc.ddd");
+
+        Set s = p.keySet();
+        try {
+            s.clear();
+        } catch (UnsupportedOperationException e) {
+        }
+        Set s1 = p.keySet();
+        if ((s == s1) || s1.isEmpty()) {
+            fail("Must return unmodifiable set");
+        }
+        if (s1.size() != 8) {
+            fail("Incorrect set size");
+        }
+        if (!s1.contains("MessageDigest.SHA-256")
+                || !s1.contains("MessageDigest.SHA-1")
+                || !s1.contains("Alg.Alias.MessageDigest.SHA1")
+                || !s1.contains("MessageDigest.abc")
+                || !s1.contains("Provider.id info")
+                || !s1.contains("Provider.id className")
+                || !s1.contains("Provider.id version")
+                || !s1.contains("Provider.id name")) {
+            fail("Incorrect set");
+        }
+    }
+
+    /*
+     * Class under test for Collection values()
+     */
+    public final void testValues() {
+        p.put("MessageDigest.SHA-256", "aaa.bbb.ccc.ddd");
+
+        Collection c = p.values();
+        try {
+            c.clear();
+        } catch (UnsupportedOperationException e) {
+        }
+        Collection c1 = p.values();
+        if ((c == c1) || c1.isEmpty()) {
+            fail("Must return unmodifiable set");
+        }
+        if (c1.size() != 8) {
+            fail("Incorrect set size " + c1.size());
+        }
+        if (!c1.contains("MyProvider") || !c1.contains("aaa.bbb.ccc.ddd")
+                || !c1.contains("Provider for testing") || !c1.contains("1.0")
+                || !c1.contains("SomeClassName") || !c1.contains("SHA-1")
+                || !c1.contains(p.getClass().getName())) {
+            fail("Incorrect set");
+        }
+    }
+
+    /*
+     * Class under test for Object put(Object, Object)
+     */
+    public final void testPutObjectObject() {
+        p.put("MessageDigest.SHA-1", "aaa.bbb.ccc.ddd");
+        p.put("Type.Algorithm", "className");
+        if (!"aaa.bbb.ccc.ddd".equals(p.getProperty("MessageDigest.SHA-1")
+                .trim())) {
+            fail("Incorrect property value");
+        }
+
+        Set services = p.getServices();
+        if (services.size() != 3) {
+            fail("incorrect size");
+        }
+        for (Iterator it = services.iterator(); it.hasNext();) {
+            Provider.Service s = (Provider.Service) it.next();
+            if ("Type".equals(s.getType())
+                    && "Algorithm".equals(s.getAlgorithm())
+                    && "className".equals(s.getClassName())) {
+                continue;
+            }
+            if ("MessageDigest".equals(s.getType())
+                    && "SHA-1".equals(s.getAlgorithm())
+                    && "aaa.bbb.ccc.ddd".equals(s.getClassName())) {
+                continue;
+            }
+            if ("MessageDigest".equals(s.getType())
+                    && "abc".equals(s.getAlgorithm())
+                    && "SomeClassName".equals(s.getClassName())) {
+                continue;
+            }
+            fail("Incorrect service");
+        }
+    }
+
+    /*
+     * Class under test for Object remove(Object)
+     */
+    public final void testRemoveObject() {
+        Object o = p.remove("MessageDigest.SHA-1");
+        if (!"SomeClassName".equals(o)) {
+            fail("Incorrect return value");
+        }
+        if (p.getProperty("MessageDigest.SHA-1") != null) {
+            fail("Provider contains properties");
+        }
+        if (p.getServices().size() != 1) {
+            fail("Service not removed");
+        }
+    }
+
+    public final void testService1() {
+        p.put("MessageDigest.SHA-1", "AnotherClassName");
+        Provider.Service s = p.getService("MessageDigest", "SHA-1");
+        if (!"AnotherClassName".equals(s.getClassName())) {
+            fail("Incorrect class name " + s.getClassName());
+        }
+    }
+
+    // public final void testService2() {
+    // Provider[] pp = Security.getProviders("MessageDigest.SHA-1");
+    // if (pp == null) {
+    // return;
+    // }
+    // Provider p2 = pp[0];
+    // String old = p2.getProperty("MessageDigest.SHA-1");
+    // try {
+    // p2.put("MessageDigest.SHA-1", "AnotherClassName");
+    // Provider.Service s = p2.getService("MessageDigest", "SHA-1");
+    // if (!"AnotherClassName".equals(s.getClassName())) {
+    // fail("Incorrect class name " + s.getClassName());
+    // }
+    // try {
+    // s.newInstance(null);
+    // fail("No expected NoSuchAlgorithmException");
+    // } catch (NoSuchAlgorithmException e) {
+    // }
+    // } finally {
+    // p2.put("MessageDigest.SHA-1", old);
+    // }
+    // }
+
+    // Regression for HARMONY-2760.
+    public void testConstructor() {
+        MyProvider myProvider = new MyProvider(null, 1, null);
+        assertNull(myProvider.getName());
+        assertNull(myProvider.getInfo());
+        assertEquals("null", myProvider.getProperty("Provider.id name"));
+        assertEquals("null", myProvider.getProperty("Provider.id info"));
+    }
+
+    public final void testGetServices() {
+        MyProvider myProvider = new MyProvider(null, 1, null);
+        Set<Provider.Service> services = myProvider.getServices();
+        assertEquals(0, services.size());
+
+        Provider.Service s[] = new Provider.Service[3];
+
+        s[0] = new Provider.Service(p, "type1", "algorithm1", "className1",
+                null, null);
+        s[1] = new Provider.Service(p, "type2", "algorithm2", "className2",
+                null, null);
+        s[2] = new Provider.Service(p, "type3", "algorithm3", "className3",
+                null, null);
+        myProvider.putService(s[0]);
+        myProvider.putService(s[1]);
+        assertEquals(2, myProvider.getNumServices());
+        Set<Service> actual = myProvider.getServices();
+
+        assertTrue(actual.contains(s[0]));
+        assertTrue(actual.contains(s[1]));
+        assertTrue(!actual.contains(s[2]));
+
+        myProvider.removeService(s[1]);
+        actual = myProvider.getServices();
+        assertEquals(1, myProvider.getNumServices());
+
+        assertTrue(actual.contains(s[0]));
+        assertTrue(!actual.contains(s[1]));
+        assertTrue(!actual.contains(s[2]));
+
+        myProvider.putService(s[2]);
+        actual = myProvider.getServices();
+        assertEquals(2, myProvider.getNumServices());
+        assertTrue(actual.contains(s[0]));
+        assertTrue(!actual.contains(s[1]));
+        assertTrue(actual.contains(s[2]));
+    }
+
+    public final void testPutService() {
+        MyProvider myProvider = new MyProvider(null, 1, null);
+        Provider.Service s[] = new Provider.Service[3];
+
+        s[0] = new Provider.Service(p, "type1", "algorithm1", "className1",
+                null, null);
+        s[1] = new Provider.Service(p, "type2", "algorithm2", "className2",
+                null, null);
+        s[2] = new Provider.Service(p, "type3", "algorithm3", "className3",
+                null, null);
+        myProvider.putService(s[0]);
+        myProvider.putService(s[1]);
+        assertEquals(2, myProvider.getNumServices());
+        Set<Service> actual = myProvider.getServices();
+
+        assertTrue(actual.contains(s[0]));
+        assertTrue(actual.contains(s[1]));
+        assertTrue(!actual.contains(s[2]));
+
+        myProvider.removeService(s[1]);
+        assertEquals(1, myProvider.getNumServices());
+        actual = myProvider.getServices();
+
+        assertTrue(actual.contains(s[0]));
+        assertTrue(!actual.contains(s[1]));
+        assertTrue(!actual.contains(s[2]));
+
+        myProvider.putService(s[2]);
+        actual = myProvider.getServices();
+        assertEquals(2, myProvider.getNumServices());
+        assertTrue(actual.contains(s[0]));
+        assertTrue(!actual.contains(s[1]));
+        assertTrue(actual.contains(s[2]));
+
+        myProvider.putService(s[2]);
+        actual = myProvider.getServices();
+        assertEquals(2, myProvider.getNumServices());
+        assertTrue(actual.contains(s[0]));
+        assertTrue(!actual.contains(s[1]));
+        assertTrue(actual.contains(s[2]));
+
+        try {
+            myProvider.putService(null);
+            fail("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    public final void testRemoveService() {
+        MyProvider myProvider = new MyProvider(null, 1, null);
+        try {
+            myProvider.removeService(null);
+            fail("NullPoiterException expected");
+        } catch (NullPointerException e) {
+            // expected
+        }
+
+        Provider.Service s[] = new Provider.Service[3];
+
+        s[0] = new Provider.Service(p, "type0", "algorithm0", "className0",
+                null, null);
+        s[1] = new Provider.Service(p, "type1", "algorithm1", "className1",
+                null, null);
+        s[2] = new Provider.Service(p, "type2", "algorithm2", "className2",
+                null, null);
+
+        try {
+            myProvider.removeService(s[0]);
+        } catch (NullPointerException e) {
+            fail("Unexpected exception");
+        }
+
+        myProvider.putService(s[0]);
+        myProvider.putService(s[1]);
+        myProvider.putService(s[2]);
+        assertEquals(3, myProvider.getNumServices());
+        Set<Service> actual = myProvider.getServices();
+
+        assertTrue(actual.contains(s[0]));
+        assertTrue(actual.contains(s[1]));
+        assertTrue(actual.contains(s[2]));
+
+        myProvider.removeService(s[1]);
+        assertEquals(2, myProvider.getNumServices());
+        actual = myProvider.getServices();
+
+        assertTrue(actual.contains(s[0]));
+        assertTrue(!actual.contains(s[1]));
+        assertTrue(actual.contains(s[2]));
+
+        myProvider.removeService(s[0]);
+        assertEquals(1, myProvider.getNumServices());
+        actual = myProvider.getServices();
+
+        assertTrue(!actual.contains(s[0]));
+        assertTrue(!actual.contains(s[1]));
+        assertTrue(actual.contains(s[2]));
+
+        myProvider.removeService(s[2]);
+        assertEquals(0, myProvider.getNumServices());
+        actual = myProvider.getServices();
+
+        assertTrue(!actual.contains(s[0]));
+        assertTrue(!actual.contains(s[1]));
+        assertTrue(!actual.contains(s[2]));
+
+        try {
+            myProvider.removeService(null);
+            fail("NullPoiterException expected");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    /*
+     * Class under test for void load(InputStream)
+     */
+    public final void testLoad() throws IOException {
+        InputStream is = new ByteArrayInputStream(writeProperties());
+        MyProvider myProvider = new MyProvider("name", 1, "info");
+        myProvider.load(is);
+        assertEquals("tests.security", myProvider.get("test.pkg"));
+        assertEquals("Unit Tests", myProvider.get("test.proj"));
+        assertNull(myProvider.get("#commented.entry"));
+
+        assertEquals("info", myProvider.get("Provider.id info"));
+        String className = myProvider.getClass().toString();
+        assertEquals(
+                className.substring("class ".length(), className.length()),
+                myProvider.get("Provider.id className"));
+        assertEquals("1.0", myProvider.get("Provider.id version"));
+
+        try {
+            myProvider.load(null);
+            fail("NullPointerException expected");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    // Regression test for Android: Check existence of RSA provider
+    public void test_RSAProvider() {
+        try {
+            final KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+            RSAKeyGenParameterSpec spec = new RSAKeyGenParameterSpec(512, BigInteger.valueOf(3));
+            kpg.initialize(spec);
+            KeyPair pair = kpg.generateKeyPair();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+    
+    protected byte[] writeProperties() throws IOException {
+        ByteArrayOutputStream bout = new ByteArrayOutputStream();
+        PrintStream ps = new PrintStream(bout);
+        ps.println("#commented.entry=Bogus");
+        ps.println("test.pkg=tests.security");
+        ps.println("test.proj=Unit Tests");
+        ps.close();
+        return bout.toByteArray();
+    }
+
+    class MyProvider extends Provider {
+        private Set<Provider.Service> services = null;
+
+        MyProvider() {
+            super("MyProvider", 1.0, "Provider for testing");
+            put("MessageDigest.SHA-1", "SomeClassName");
+            put("MessageDigest.abc", "SomeClassName");
+            put("Alg.Alias.MessageDigest.SHA1", "SHA-1");
+            if (services != null) {
+                services.clear();
+            } else {
+                services = new HashSet<Service>();
+            }
+        }
+
+        MyProvider(String name, double version, String info) {
+            super(name, version, info);
+            if (services != null) {
+                services.clear();
+            } else {
+                services = new HashSet<Service>();
+            }
+        }
+
+        public void putService(Provider.Service s) {
+            super.putService(s);
+            services.add(s);
+        }
+
+        public void removeService(Provider.Service s) {
+            super.removeService(s);
+            services.remove(s);
+        }
+
+        public int getNumServices() {
+            return services.size();
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/tests/java/security/SecureClassLoaderTest.java b/libcore/security/src/test/java/tests/java/security/SecureClassLoaderTest.java
new file mode 100644
index 0000000..87568c0
--- /dev/null
+++ b/libcore/security/src/test/java/tests/java/security/SecureClassLoaderTest.java
@@ -0,0 +1,250 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+ * @author Alexander V. Astapchuk
+ * @version $Revision$
+ */
+
+package tests.java.security;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.ByteBuffer;
+import java.security.CodeSource;
+import java.security.PermissionCollection;
+import java.security.ProtectionDomain;
+import java.security.SecureClassLoader;
+import java.security.cert.Certificate;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit test for SecureClassLoader.
+ * 
+ */
+
+public class SecureClassLoaderTest extends TestCase {
+    /**
+     * Entry point for stand alone runs.
+     * 
+     * @param args
+     *            command line parameters
+     */
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(SecureClassLoaderTest.class);
+    }
+
+    /**
+     * A class name for the class presented as {@link klassData bytecode below}
+     */
+    private static final String klassName = "HiWorld";
+
+    /**
+     * Some class presented as bytecode<br>
+     * Class src:<br>
+     * <p>
+     * <code>public class HiWorld {
+     *     public static void main(String[] args) 
+     *         {System.out.println("Hi, world!"); } 
+     *    }
+     * </code>
+     */
+
+    private static final byte[] klassData = { (byte) 0xCA, (byte) 0xFE,
+            (byte) 0xBA, (byte) 0xBE, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x2E, (byte) 0x00, (byte) 0x22, (byte) 0x01, (byte) 0x00,
+            (byte) 0x07, (byte) 0x48, (byte) 0x69, (byte) 0x57, (byte) 0x6F,
+            (byte) 0x72, (byte) 0x6C, (byte) 0x64, (byte) 0x07, (byte) 0x00,
+            (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x10, (byte) 0x6A,
+            (byte) 0x61, (byte) 0x76, (byte) 0x61, (byte) 0x2F, (byte) 0x6C,
+            (byte) 0x61, (byte) 0x6E, (byte) 0x67, (byte) 0x2F, (byte) 0x4F,
+            (byte) 0x62, (byte) 0x6A, (byte) 0x65, (byte) 0x63, (byte) 0x74,
+            (byte) 0x07, (byte) 0x00, (byte) 0x03, (byte) 0x01, (byte) 0x00,
+            (byte) 0x06, (byte) 0x3C, (byte) 0x69, (byte) 0x6E, (byte) 0x69,
+            (byte) 0x74, (byte) 0x3E, (byte) 0x01, (byte) 0x00, (byte) 0x03,
+            (byte) 0x28, (byte) 0x29, (byte) 0x56, (byte) 0x01, (byte) 0x00,
+            (byte) 0x04, (byte) 0x43, (byte) 0x6F, (byte) 0x64, (byte) 0x65,
+            (byte) 0x0C, (byte) 0x00, (byte) 0x05, (byte) 0x00, (byte) 0x06,
+            (byte) 0x0A, (byte) 0x00, (byte) 0x04, (byte) 0x00, (byte) 0x08,
+            (byte) 0x01, (byte) 0x00, (byte) 0x0F, (byte) 0x4C, (byte) 0x69,
+            (byte) 0x6E, (byte) 0x65, (byte) 0x4E, (byte) 0x75, (byte) 0x6D,
+            (byte) 0x62, (byte) 0x65, (byte) 0x72, (byte) 0x54, (byte) 0x61,
+            (byte) 0x62, (byte) 0x6C, (byte) 0x65, (byte) 0x01, (byte) 0x00,
+            (byte) 0x12, (byte) 0x4C, (byte) 0x6F, (byte) 0x63, (byte) 0x61,
+            (byte) 0x6C, (byte) 0x56, (byte) 0x61, (byte) 0x72, (byte) 0x69,
+            (byte) 0x61, (byte) 0x62, (byte) 0x6C, (byte) 0x65, (byte) 0x54,
+            (byte) 0x61, (byte) 0x62, (byte) 0x6C, (byte) 0x65, (byte) 0x01,
+            (byte) 0x00, (byte) 0x04, (byte) 0x74, (byte) 0x68, (byte) 0x69,
+            (byte) 0x73, (byte) 0x01, (byte) 0x00, (byte) 0x09, (byte) 0x4C,
+            (byte) 0x48, (byte) 0x69, (byte) 0x57, (byte) 0x6F, (byte) 0x72,
+            (byte) 0x6C, (byte) 0x64, (byte) 0x3B, (byte) 0x01, (byte) 0x00,
+            (byte) 0x04, (byte) 0x6D, (byte) 0x61, (byte) 0x69, (byte) 0x6E,
+            (byte) 0x01, (byte) 0x00, (byte) 0x16, (byte) 0x28, (byte) 0x5B,
+            (byte) 0x4C, (byte) 0x6A, (byte) 0x61, (byte) 0x76, (byte) 0x61,
+            (byte) 0x2F, (byte) 0x6C, (byte) 0x61, (byte) 0x6E, (byte) 0x67,
+            (byte) 0x2F, (byte) 0x53, (byte) 0x74, (byte) 0x72, (byte) 0x69,
+            (byte) 0x6E, (byte) 0x67, (byte) 0x3B, (byte) 0x29, (byte) 0x56,
+            (byte) 0x01, (byte) 0x00, (byte) 0x10, (byte) 0x6A, (byte) 0x61,
+            (byte) 0x76, (byte) 0x61, (byte) 0x2F, (byte) 0x6C, (byte) 0x61,
+            (byte) 0x6E, (byte) 0x67, (byte) 0x2F, (byte) 0x53, (byte) 0x79,
+            (byte) 0x73, (byte) 0x74, (byte) 0x65, (byte) 0x6D, (byte) 0x07,
+            (byte) 0x00, (byte) 0x10, (byte) 0x01, (byte) 0x00, (byte) 0x03,
+            (byte) 0x6F, (byte) 0x75, (byte) 0x74, (byte) 0x01, (byte) 0x00,
+            (byte) 0x15, (byte) 0x4C, (byte) 0x6A, (byte) 0x61, (byte) 0x76,
+            (byte) 0x61, (byte) 0x2F, (byte) 0x69, (byte) 0x6F, (byte) 0x2F,
+            (byte) 0x50, (byte) 0x72, (byte) 0x69, (byte) 0x6E, (byte) 0x74,
+            (byte) 0x53, (byte) 0x74, (byte) 0x72, (byte) 0x65, (byte) 0x61,
+            (byte) 0x6D, (byte) 0x3B, (byte) 0x0C, (byte) 0x00, (byte) 0x12,
+            (byte) 0x00, (byte) 0x13, (byte) 0x09, (byte) 0x00, (byte) 0x11,
+            (byte) 0x00, (byte) 0x14, (byte) 0x01, (byte) 0x00, (byte) 0x0A,
+            (byte) 0x48, (byte) 0x69, (byte) 0x2C, (byte) 0x20, (byte) 0x77,
+            (byte) 0x6F, (byte) 0x72, (byte) 0x6C, (byte) 0x64, (byte) 0x21,
+            (byte) 0x08, (byte) 0x00, (byte) 0x16, (byte) 0x01, (byte) 0x00,
+            (byte) 0x13, (byte) 0x6A, (byte) 0x61, (byte) 0x76, (byte) 0x61,
+            (byte) 0x2F, (byte) 0x69, (byte) 0x6F, (byte) 0x2F, (byte) 0x50,
+            (byte) 0x72, (byte) 0x69, (byte) 0x6E, (byte) 0x74, (byte) 0x53,
+            (byte) 0x74, (byte) 0x72, (byte) 0x65, (byte) 0x61, (byte) 0x6D,
+            (byte) 0x07, (byte) 0x00, (byte) 0x18, (byte) 0x01, (byte) 0x00,
+            (byte) 0x07, (byte) 0x70, (byte) 0x72, (byte) 0x69, (byte) 0x6E,
+            (byte) 0x74, (byte) 0x6C, (byte) 0x6E, (byte) 0x01, (byte) 0x00,
+            (byte) 0x15, (byte) 0x28, (byte) 0x4C, (byte) 0x6A, (byte) 0x61,
+            (byte) 0x76, (byte) 0x61, (byte) 0x2F, (byte) 0x6C, (byte) 0x61,
+            (byte) 0x6E, (byte) 0x67, (byte) 0x2F, (byte) 0x53, (byte) 0x74,
+            (byte) 0x72, (byte) 0x69, (byte) 0x6E, (byte) 0x67, (byte) 0x3B,
+            (byte) 0x29, (byte) 0x56, (byte) 0x0C, (byte) 0x00, (byte) 0x1A,
+            (byte) 0x00, (byte) 0x1B, (byte) 0x0A, (byte) 0x00, (byte) 0x19,
+            (byte) 0x00, (byte) 0x1C, (byte) 0x01, (byte) 0x00, (byte) 0x04,
+            (byte) 0x61, (byte) 0x72, (byte) 0x67, (byte) 0x73, (byte) 0x01,
+            (byte) 0x00, (byte) 0x13, (byte) 0x5B, (byte) 0x4C, (byte) 0x6A,
+            (byte) 0x61, (byte) 0x76, (byte) 0x61, (byte) 0x2F, (byte) 0x6C,
+            (byte) 0x61, (byte) 0x6E, (byte) 0x67, (byte) 0x2F, (byte) 0x53,
+            (byte) 0x74, (byte) 0x72, (byte) 0x69, (byte) 0x6E, (byte) 0x67,
+            (byte) 0x3B, (byte) 0x01, (byte) 0x00, (byte) 0x0A, (byte) 0x53,
+            (byte) 0x6F, (byte) 0x75, (byte) 0x72, (byte) 0x63, (byte) 0x65,
+            (byte) 0x46, (byte) 0x69, (byte) 0x6C, (byte) 0x65, (byte) 0x01,
+            (byte) 0x00, (byte) 0x0C, (byte) 0x48, (byte) 0x69, (byte) 0x57,
+            (byte) 0x6F, (byte) 0x72, (byte) 0x6C, (byte) 0x64, (byte) 0x2E,
+            (byte) 0x6A, (byte) 0x61, (byte) 0x76, (byte) 0x61, (byte) 0x00,
+            (byte) 0x21, (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x04,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x02, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x05,
+            (byte) 0x00, (byte) 0x06, (byte) 0x00, (byte) 0x01, (byte) 0x00,
+            (byte) 0x07, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x2F,
+            (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x05, (byte) 0x2A, (byte) 0xB7,
+            (byte) 0x00, (byte) 0x09, (byte) 0xB1, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x0A, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x06, (byte) 0x00, (byte) 0x01,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x14, (byte) 0x00,
+            (byte) 0x0B, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0C,
+            (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x05, (byte) 0x00, (byte) 0x0C, (byte) 0x00, (byte) 0x0D,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x09, (byte) 0x00,
+            (byte) 0x0E, (byte) 0x00, (byte) 0x0F, (byte) 0x00, (byte) 0x01,
+            (byte) 0x00, (byte) 0x07, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x37, (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x01,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x09, (byte) 0xB2,
+            (byte) 0x00, (byte) 0x15, (byte) 0x12, (byte) 0x17, (byte) 0xB6,
+            (byte) 0x00, (byte) 0x1D, (byte) 0xB1, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x0A, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x0A, (byte) 0x00, (byte) 0x02,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x17, (byte) 0x00,
+            (byte) 0x08, (byte) 0x00, (byte) 0x18, (byte) 0x00, (byte) 0x0B,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0C, (byte) 0x00,
+            (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x09,
+            (byte) 0x00, (byte) 0x1E, (byte) 0x00, (byte) 0x1F, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x20,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x00,
+            (byte) 0x21, };
+
+    /**
+     * Tests default ctor
+     */
+    public void testSecureClassLoader() {
+        new MyClassLoader();
+    }
+
+    /**
+     * Tests SecureClassLoader(ClassLoader)
+     */
+    public void testSecureClassLoaderClassLoader() throws Exception {
+        URL[] urls = new URL[] { new URL("http://localhost") };
+        URLClassLoader ucl = URLClassLoader.newInstance(urls);
+        new MyClassLoader(ucl);
+    }
+
+    /**
+     * Tests getPermission
+     */
+    public void testGetPermissions() throws Exception {
+        URL url = new URL("http://localhost");
+        CodeSource cs = new CodeSource(url, (Certificate[]) null);
+        MyClassLoader ldr = new MyClassLoader();
+        ldr.getPerms(null);
+        ldr.getPerms(cs);
+    }
+
+    /**
+     * Tests defineClass(String, byte[], int, int, CodeSource)
+     */
+    public void testDefineClassStringbyteArrayintintCodeSource() {
+        MyClassLoader ldr = new MyClassLoader();
+        Class klass = ldr.define(null, klassData, 0, klassData.length, null);
+        assertEquals(klass.getName(), klassName);
+    }
+
+    /**
+     * Tests defineClass(String, ByteBuffer, CodeSource)
+     */
+    public void testDefineClassStringByteBufferCodeSource() {
+        MyClassLoader ldr = new MyClassLoader();
+        ByteBuffer bbuf = ByteBuffer.wrap(klassData);
+        Class klass = ldr.define(null, bbuf, null);
+        assertEquals(klass.getName(), klassName);
+    }
+
+    class MyClassLoader extends SecureClassLoader {
+
+        public MyClassLoader() {
+            super();
+        }
+
+        public MyClassLoader(ClassLoader parent) {
+            super(parent);
+        }
+
+        public PermissionCollection getPerms(CodeSource codesource) {
+            return super.getPermissions(codesource);
+        }
+
+        public Class define(String name, byte[] bytes) {
+            return defineClass(name, bytes, 0, bytes.length,
+                    (ProtectionDomain) null);
+        }
+
+        public Class define(String name, ByteBuffer b, CodeSource cs) {
+            return defineClass(name, b, cs);
+        }
+
+        public Class define(String name, byte[] b, int off, int len,
+                CodeSource cs) {
+            return defineClass(name, b, off, len, cs);
+        }
+
+    }
+}
diff --git a/libcore/security/src/test/java/tests/java/security/SecureRandomTest.java b/libcore/security/src/test/java/tests/java/security/SecureRandomTest.java
new file mode 100644
index 0000000..bc33594
--- /dev/null
+++ b/libcore/security/src/test/java/tests/java/security/SecureRandomTest.java
@@ -0,0 +1,198 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris V. Kuznetsov
+* @version $Revision$
+*/
+
+package tests.java.security;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.Security;
+
+import org.apache.harmony.security.tests.support.RandomImpl;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>SecureRandom</code> constructor and methods
+ * 
+ */
+public class SecureRandomTest extends TestCase {
+
+    /**
+     * SRProvider
+     */
+    Provider p;
+    
+    /*
+     * @see TestCase#setUp()
+     */
+    protected void setUp() throws Exception {
+        super.setUp();
+        p = new SRProvider();
+        Security.insertProviderAt(p, 1);
+    }
+
+    /*
+     * @see TestCase#tearDown()
+     */
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        Security.removeProvider(p.getName());
+    }
+
+    public final void testNext() {
+        MySecureRandom sr = new MySecureRandom();
+        if (sr.nextElement(1) != 1 || sr.nextElement(2) != 3 || sr.nextElement(3) != 7) {
+            fail("next failed");            
+        }
+    }
+
+    /*
+     * Class under test for void setSeed(long)
+     */
+    public final void testSetSeedlong() {
+        SecureRandom sr = new SecureRandom();
+        sr.setSeed(12345);
+        if (!RandomImpl.runEngineSetSeed) {
+            fail("setSeed failed");
+        }    
+    }
+
+    public final void testNextBytes() {
+        byte[] b = new byte[5];
+        SecureRandom sr = new SecureRandom();
+        sr.nextBytes(b);
+        for (int i = 0; i < b.length; i++) {
+            if (b[i] != (byte)(i + 0xF1)) {
+                fail("nextBytes failed");
+            }
+        }
+    }
+
+    /*
+     * Class under test for void SecureRandom()
+     */
+    public final void testSecureRandom() {
+        SecureRandom sr = new SecureRandom();
+        if (!sr.getAlgorithm().equals("someRandom")  ||
+                sr.getProvider()!= p) {
+            fail("incorrect SecureRandom implementation" + p.getName());
+        }    
+    }
+
+    /*
+     * Class under test for void SecureRandom(byte[])
+     */
+    public final void testSecureRandombyteArray() {
+        byte[] b = {1,2,3};
+        new SecureRandom(b);
+        
+        if (!RandomImpl.runEngineSetSeed) {
+            fail("No setSeed");
+        }
+    }
+
+    /*
+     * Class under test for SecureRandom getInstance(String)
+     */
+    public final void testGetInstanceString() {
+        SecureRandom sr = null;
+        try {
+            sr = SecureRandom.getInstance("someRandom");    
+        } catch (NoSuchAlgorithmException e) {
+            fail(e.toString());
+        }
+        if (sr.getProvider() != p || !"someRandom".equals(sr.getAlgorithm())) {
+            fail("getInstance failed");
+        }    
+    }
+
+    /*
+     * Class under test for SecureRandom getInstance(String, String)
+     */
+    public final void testGetInstanceStringString() throws Exception {
+        SecureRandom sr = SecureRandom.getInstance("someRandom", "SRProvider");    
+        if (sr.getProvider() != p || !"someRandom".equals(sr.getAlgorithm())) {
+            fail("getInstance failed");
+        }    
+    }
+
+    /*
+     * Class under test for SecureRandom getInstance(String, Provider)
+     */
+    public final void testGetInstanceStringProvider() throws Exception {
+        Provider p = new SRProvider();
+        SecureRandom sr = SecureRandom.getInstance("someRandom", p);
+        if (sr.getProvider() != p || !"someRandom".equals(sr.getAlgorithm())) {
+            fail("getInstance failed");
+        }    
+    }
+
+    /*
+     * Class under test for void setSeed(byte[])
+     */
+    public final void testSetSeedbyteArray() {
+        byte[] b = {1,2,3};
+        SecureRandom sr = new SecureRandom();
+        sr.setSeed(b);
+        if (!RandomImpl.runEngineSetSeed) {
+            fail("setSeed failed");
+        }
+    }
+
+    public final void testGetSeed() {
+        byte[] b = SecureRandom.getSeed(4);
+        if( b.length != 4) {
+            fail("getSeed failed");
+        }
+    }
+
+    public final void testGenerateSeed() {
+        SecureRandom sr = new SecureRandom();
+        byte[] b = sr.generateSeed(4);
+        for (int i = 0; i < b.length; i++) {
+            if (b[i] != (byte)i) {
+                fail("generateSeed failed");
+            }
+        }
+    }
+    
+    
+    
+    public class SRProvider extends Provider {
+        public SRProvider() {
+            super("SRProvider", 1.0, "SRProvider for testing");
+            put("SecureRandom.someRandom",
+                    "org.apache.harmony.security.tests.support.RandomImpl");
+        }
+    }
+    
+    class MySecureRandom extends SecureRandom {
+        public MySecureRandom(){
+            super();
+        }
+        
+        public int nextElement(int numBits) {
+            return super.next(numBits);
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/tests/java/security/SignatureTest.java b/libcore/security/src/test/java/tests/java/security/SignatureTest.java
new file mode 100644
index 0000000..0719e49
--- /dev/null
+++ b/libcore/security/src/test/java/tests/java/security/SignatureTest.java
@@ -0,0 +1,372 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/**
+* @author Boris V. Kuznetsov
+* @version $Revision$
+*/
+
+package tests.java.security;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+
+import org.apache.harmony.security.tests.support.MySignature1;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for <code>Signature</code> constructor and methods
+ * 
+ */
+public class SignatureTest extends TestCase {
+
+    /*
+     * Class under test for Signature(String)
+     */
+    public void testConstructor() {
+        String [] algorithms = { "SHA256WITHRSA", "NONEWITHDSA", "SHA384WITHRSA",
+            "MD2WITHRSA", "MD5ANDSHA1WITHRSA", "SHA512WITHRSA",
+            "SHA1WITHRSA", "SHA1WITHDSA", "MD5WITHRSA" };
+        for (int i = 0; i < algorithms.length; i ++) {
+            MySignature1 s = new MySignature1(algorithms[i]);
+            assertEquals(algorithms[i],s.getAlgorithm());
+            assertNull(s.getProvider());
+            assertEquals(0, s.getState());
+        }
+        
+        MySignature1 s1 = new MySignature1(null);
+        assertNull(s1.getAlgorithm());
+        assertNull(s1.getProvider());
+        assertEquals(0, s1.getState());
+    
+        MySignature1 s2 = new MySignature1("ABCD@#&^%$)(*&");
+        assertEquals("ABCD@#&^%$)(*&", s2.getAlgorithm());
+        assertNull(s2.getProvider());
+        assertEquals(0, s2.getState());
+    }
+    
+    /*
+     * Class under test for Object clone()
+     */
+    public void testClone() {
+        MySignature1 s = new MySignature1("ABC");
+        try {
+            s.clone();
+            fail("No expected CloneNotSupportedException");
+        } catch (CloneNotSupportedException e) {    
+        }    
+    }
+
+    public void testGetProvider() {
+        MySignature1 s = new MySignature1("ABC");
+        
+        assertEquals("state", MySignature1.UNINITIALIZED, s.getState());
+        assertNull("provider", s.getProvider());
+    }
+
+    public void testGetAlgorithm() {
+        MySignature1 s = new MySignature1("ABC");
+
+        assertEquals("state", MySignature1.UNINITIALIZED, s.getState());
+        assertEquals("algorithm", "ABC", s.getAlgorithm());
+    }
+
+    /*
+     * Class under test for void initVerify(PublicKey)
+     */
+    public void testInitVerifyPublicKey() throws InvalidKeyException {
+        MySignature1 s = new MySignature1("ABC");
+
+        s.initVerify(new MyPublicKey());
+        assertEquals("state", MySignature1.VERIFY, s.getState());
+        assertTrue("initVerify() failed", s.runEngineInitVerify);
+    }
+
+    /*
+     * Class under test for void initVerify(Certificate)
+     */
+    public void testInitVerifyCertificate() throws InvalidKeyException {
+        MySignature1 s = new MySignature1("ABC");
+
+        s.initVerify(new MyCertificate());
+        assertEquals("state", MySignature1.VERIFY, s.getState());
+        assertTrue("initVerify() failed", s.runEngineInitVerify);
+    }
+
+    /*
+     * Class under test for void initSign(PrivateKey)
+     */
+    public void testInitSignPrivateKey() throws InvalidKeyException {
+        MySignature1 s = new MySignature1("ABC");
+
+        s.initSign(new MyPrivateKey());
+        assertEquals("state", MySignature1.SIGN, s.getState());
+        assertTrue("initSign() failed", s.runEngineInitSign);
+    }
+
+    /*
+     * Class under test for void initSign(PrivateKey, SecureRandom)
+     */
+    public void testInitSignPrivateKeySecureRandom() throws InvalidKeyException {
+        MySignature1 s = new MySignature1("ABC");
+
+        s.initSign(new MyPrivateKey(), new SecureRandom());
+        assertEquals("state", MySignature1.SIGN, s.getState());
+        assertTrue("initSign() failed", s.runEngineInitSign);
+    }
+
+    /*
+     * Class under test for byte[] sign()
+     */
+    public void testSign() throws Exception {
+        MySignature1 s = new MySignature1("ABC");
+        try {
+            s.sign();
+            fail("No expected SignatureException");
+        } catch (SignatureException e) {        
+        }
+
+        s.initVerify(new MyPublicKey());
+        
+        try {
+            s.sign();
+            fail("No expected SignatureException");
+        } catch (SignatureException e) {        
+        }
+        
+        s.initSign(new MyPrivateKey());
+        s.sign();
+        assertEquals("state", MySignature1.SIGN, s.getState());
+        assertTrue("sign() failed", s.runEngineSign);
+    }
+
+    /*
+     * Class under test for sign(byte[], offset, len)
+     */
+    public void testSignbyteintint() throws Exception {
+        MySignature1 s = new MySignature1("ABC");
+        byte[] outbuf = new byte [10];
+        try {
+            s.sign(outbuf, 0, outbuf.length);
+            fail("No expected SignatureException");
+        } catch (SignatureException e) {        
+        }
+
+        s.initVerify(new MyPublicKey());
+        
+        try {
+            s.sign(outbuf, 0, outbuf.length);
+            fail("No expected SignatureException");
+        } catch (SignatureException e) {        
+        }
+        
+        s.initSign(new MyPrivateKey());
+        assertEquals(s.getBufferLength(), s.sign(outbuf, 0, outbuf.length));
+        assertEquals("state", MySignature1.SIGN, s.getState());
+        assertTrue("sign() failed", s.runEngineSign);
+    }
+
+    
+    /*
+     * Class under test for boolean verify(byte[])
+     */
+    public void testVerifybyteArray() throws Exception {
+        MySignature1 s = new MySignature1("ABC");
+        byte[] b = {1, 2, 3, 4};
+        try {
+            s.verify(b);
+            fail("No expected SignatureException");
+        } catch (SignatureException e) {        
+        }
+
+        s.initSign(new MyPrivateKey());
+        try {
+            s.verify(b);
+            fail("No expected SignatureException");
+        } catch (SignatureException e) {        
+        }
+        
+        s.initVerify(new MyPublicKey());
+        s.verify(b);
+        assertEquals("state", MySignature1.VERIFY, s.getState());
+        assertTrue("verify() failed", s.runEngineVerify);
+    }
+
+    /*
+     * Class under test for boolean verify(byte[], int, int)
+     */
+    public void testVerifybyteArrayintint() throws Exception {
+        MySignature1 s = new MySignature1("ABC");
+        byte[] b = {1, 2, 3, 4};
+        try {
+            s.verify(b, 0, 3);
+            fail("No expected SignatureException");
+        } catch (SignatureException e) {        
+        }
+
+        s.initSign(new MyPrivateKey());
+
+        try {
+            s.verify(b, 0, 3);
+            fail("No expected SignatureException");
+        } catch (SignatureException e) {        
+        }
+        
+        s.initVerify(new MyPublicKey());
+        
+        try {
+            s.verify(b, 0, 5);
+            fail("No expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {        
+        }
+        
+        s.verify(b, 0, 3);
+        assertEquals("state", MySignature1.VERIFY, s.getState());
+        assertTrue("verify() failed", s.runEngineVerify);
+    }
+
+    /*
+     * Class under test for void update(byte)
+     */
+    public void testUpdatebyte() throws Exception {
+        MySignature1 s = new MySignature1("ABC");
+        try {
+            s.update((byte)1);
+            fail("No expected SignatureException");
+        } catch (SignatureException e) {        
+        }
+
+        s.initVerify(new MyPublicKey());
+        s.update((byte) 1);
+        s.initSign(new MyPrivateKey());
+        s.update((byte) 1);
+
+        assertEquals("state", MySignature1.SIGN, s.getState());
+        assertTrue("update() failed", s.runEngineUpdate1);
+    }
+
+    /*
+     * Class under test for void update(byte[])
+     */
+    public void testUpdatebyteArray() throws Exception {
+        MySignature1 s = new MySignature1("ABC");
+        byte[] b = {1, 2, 3, 4};
+        try {
+            s.update(b);
+            fail("No expected SignatureException");
+        } catch (SignatureException e) {        
+        }
+
+        s.initVerify(new MyPublicKey());
+        s.update(b);
+        s.initSign(new MyPrivateKey());
+        s.update(b);
+
+        assertEquals("state", MySignature1.SIGN, s.getState());
+        assertTrue("update() failed", s.runEngineUpdate2);
+    }
+
+    /*
+     * Class under test for void update(byte[], int, int)
+     */
+    public void testUpdatebyteArrayintint() throws Exception {
+        MySignature1 s = new MySignature1("ABC");
+        byte[] b = {1, 2, 3, 4};
+        try {
+            s.update(b, 0, 3);
+            fail("No expected SignatureException");
+        } catch (SignatureException e) {        
+        }
+
+        s.initVerify(new MyPublicKey());
+        s.update(b, 0, 3);
+        s.initSign(new MyPrivateKey());
+        s.update(b, 0, 3);
+
+        assertEquals("state", MySignature1.SIGN, s.getState());
+        assertTrue("update() failed", s.runEngineUpdate2);
+    }
+
+    /*
+     * Class under test for void setParameter(String, Object)
+     */
+    @SuppressWarnings("deprecation")
+    public void testSetParameterStringObject() {
+        MySignature1 s = new MySignature1("ABC");
+        s.setParameter("aaa", new Object());
+    }
+
+    /*
+     * Class under test for void setParameter(AlgorithmParameterSpec)
+     */
+    public void testSetParameterAlgorithmParameterSpec() throws InvalidAlgorithmParameterException {
+        MySignature1 s = new MySignature1("ABC");
+        try {
+            s.setParameter((java.security.spec.AlgorithmParameterSpec)null);
+            fail("No expected UnsupportedOperationException");
+        } catch (UnsupportedOperationException e){    
+        }
+    }
+    @SuppressWarnings("deprecation")
+    public void testGetParameter() {
+        MySignature1 s = new MySignature1("ABC");
+        s.getParameter("aaa");
+    }
+    
+    private class MyKey implements Key {
+        public String getFormat() {
+            return "123";
+        }
+        public byte[] getEncoded() {
+            return null;
+        }
+        public String getAlgorithm() {
+            return "aaa";
+        }        
+    }
+    
+    private class MyPublicKey extends MyKey implements PublicKey {}
+
+    private class MyPrivateKey extends MyKey implements PrivateKey {}
+    
+    private class MyCertificate extends java.security.cert.Certificate {    
+        public  MyCertificate() {
+            super("MyCertificateType");
+        }
+        
+        public PublicKey getPublicKey() {
+            return new MyPublicKey();
+        }
+        
+        public byte[] getEncoded() {
+            return null;
+        }
+        public void verify(PublicKey key) {}
+        
+        public void verify(PublicKey key, String sigProvider) {}
+        
+        public String toString() {
+            return "MyCertificate";
+        }
+    }
+}
diff --git a/libcore/security/src/test/java/tests/security/AccessControllerTest.java b/libcore/security/src/test/java/tests/security/AccessControllerTest.java
new file mode 100644
index 0000000..18bffc6
--- /dev/null
+++ b/libcore/security/src/test/java/tests/security/AccessControllerTest.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.security;
+
+import java.lang.reflect.Field;
+import java.security.AccessController;
+import java.security.BasicPermission;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+
+import junit.framework.TestCase;
+
+public class AccessControllerTest extends TestCase {
+    
+    private static void setProtectionDomain(Class c, ProtectionDomain pd){
+        Field fields[] = Class.class.getDeclaredFields();
+        for(Field f : fields){
+            if("pd".equals(f.getName())){
+                f.setAccessible(true);
+                try {
+                    f.set(c, pd);
+                } catch (IllegalArgumentException e) {
+                    fail("Protection domain could not be set");
+                } catch (IllegalAccessException e) {
+                    fail("Protection domain could not be set");
+                }
+                break;
+            }
+        }
+    }
+
+    SecurityManager old;
+    TestPermission p;
+    CodeSource codeSource;
+    PermissionCollection c0, c1, c2;
+    
+    public static void main(String[] args) throws Exception {
+        AccessControllerTest t = new AccessControllerTest();
+        t.setUp();
+        t.test_do_privileged1();
+        t.tearDown();
+        System.out.println("\nok\n");
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        old = System.getSecurityManager();
+        codeSource = null;
+        p = new TestPermission();
+        c0 = p.newPermissionCollection();
+        c1 = p.newPermissionCollection();
+        c2 = p.newPermissionCollection();
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        System.setSecurityManager(old);
+        super.tearDown();
+    }
+    
+    private void waitForDebugger(){
+        boolean wait = true;
+        while(wait){
+            System.out.print(".");
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+            }
+        }
+        System.out.println();
+    }
+    
+    public void test_do_privileged1() throws Exception {
+        // add TestPermission to T1 and T2 only
+        c1.add(p);
+        c2.add(p);
+        setProtectionDomain(T0.class, new ProtectionDomain(codeSource, c0));
+        setProtectionDomain(T1.class, new ProtectionDomain(codeSource, c1));
+        setProtectionDomain(T2.class, new ProtectionDomain(codeSource, c2));
+        
+//        waitForDebugger();
+       
+        System.setSecurityManager(new SecurityManager());
+        try {
+            String res = T0.f0();
+            fail("expected java.security.AccessControlException");
+        }
+        catch(java.security.AccessControlException e){
+            // expected behavior
+        }
+        catch(Exception e){
+            fail("expected java.security.AccessControlException, got "+e.getClass().getName());
+        }
+    }
+    
+    public void test_do_privileged2() {
+        // add TestPermission to T0, T1, T2
+        c0.add(p);
+        c1.add(p);
+        c2.add(p);
+        setProtectionDomain(T0.class, new ProtectionDomain(codeSource, c0));
+        setProtectionDomain(T1.class, new ProtectionDomain(codeSource, c1));
+        setProtectionDomain(T2.class, new ProtectionDomain(codeSource, c2));
+
+        System.setSecurityManager(new SecurityManager());
+        try {
+            String res = T0.f0();
+            assertEquals("ok", res);
+        }
+        catch(java.security.AccessControlException e){
+            fail("expected no java.security.AccessControlException");
+        }
+        catch(Exception e){
+            fail("expected no exception, got "+e.getClass().getName());
+        }
+    }
+
+    public void test_do_privileged3() {
+        // add TestPermission to T1 and T2, and call it with doPrivileged from T1
+        c1.add(p);
+        c2.add(p);
+        setProtectionDomain(T0.class, new ProtectionDomain(codeSource, c0));
+        setProtectionDomain(T1.class, new ProtectionDomain(codeSource, c1));
+        setProtectionDomain(T2.class, new ProtectionDomain(codeSource, c2));
+        
+        System.setSecurityManager(new SecurityManager());
+        try {
+            String res = T0.f0_priv();
+            assertEquals("ok", res);
+        }
+        catch(java.security.AccessControlException e){
+            fail("expected no java.security.AccessControlException");
+        }
+        catch(Exception e){
+            fail("expected no exception, got "+e.getClass().getName());
+        }
+    }
+    
+    static class T0 {
+        static String f0(){
+            return T1.f1();
+        }
+        static String f0_priv(){
+            return T1.f1_priv();
+        }
+    }
+    
+    static class T1 {
+        static String f1(){
+            return T2.f2();
+        }
+        static String f1_priv(){
+            return AccessController.doPrivileged(
+                new PrivilegedAction<String>(){
+                    public String run() {
+                        return T2.f2();
+                    }
+                }
+            );
+        }
+    }
+    
+    static class T2 {
+        static String f2(){
+            SecurityManager s = System.getSecurityManager();
+            assertNotNull(s);
+            s.checkPermission(new TestPermission());
+            return "ok";
+        }
+    }
+    
+    static class TestPermission extends BasicPermission {
+        public TestPermission(){ super("TestPermission"); }
+    
+        @Override
+        public boolean implies(Permission permission) {
+            return permission instanceof TestPermission;
+        }
+    }
+    
+}
diff --git a/libcore/security/src/test/java/tests/security/AllTests.java b/libcore/security/src/test/java/tests/security/AllTests.java
new file mode 100644
index 0000000..05a1a34
--- /dev/null
+++ b/libcore/security/src/test/java/tests/security/AllTests.java
@@ -0,0 +1,43 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.security;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Test suite that includes all tests for the security project.
+ */
+public class AllTests {
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(AllTests.suite());
+    }
+
+    public static Test suite() {
+        TestSuite suite = new TestSuite("All security test suites");
+        // $JUnit-BEGIN$
+        suite.addTest(org.apache.harmony.security.tests.java.security.AllTests.suite());
+        suite.addTest(tests.api.java.security.AllTests.suite());
+        suite.addTest(tests.java.security.AllTests.suite());
+
+        suite.addTest(tests.security.SecurityPermissionsTest.suite());
+        suite.addTestSuite(tests.security.AccessControllerTest.class);
+        // $JUnit-END$
+        return suite;
+    }
+}
diff --git a/libcore/security/src/test/java/tests/security/SecurityPermissionsTest.java b/libcore/security/src/test/java/tests/security/SecurityPermissionsTest.java
new file mode 100644
index 0000000..9a06e27
--- /dev/null
+++ b/libcore/security/src/test/java/tests/security/SecurityPermissionsTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.security;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileFilter;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.NotActiveException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.io.SerializablePermission;
+import java.io.StreamCorruptedException;
+import java.security.Permission;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/*
+ * This class tests the secrity permissions which are documented in
+ * http://java.sun.com/j2se/1.5.0/docs/guide/security/permissions.html#PermsAndMethods
+ */
+public class SecurityPermissionsTest extends TestCase {
+    
+    public static final Test suite() {
+        TestSuite suite = new TestSuite("Tests for security permissions");
+
+        suite.addTestSuite(tests.security.permissions.JavaIoFileStreamTest.class);
+        suite.addTestSuite(tests.security.permissions.JavaIoRandomAccessFileTest.class);
+        suite.addTestSuite(tests.security.permissions.JavaIoFileTest.class);
+        suite.addTestSuite(tests.security.permissions.JavaIoObjectStreamTest.class);
+        suite.addTestSuite(tests.security.permissions.JavaLangSystemTest.class);
+        suite.addTestSuite(tests.security.permissions.JavaLangClassTest.class);
+        suite.addTestSuite(tests.security.permissions.JavaLangClassLoaderTest.class);
+        suite.addTestSuite(tests.security.permissions.JavaSecurityPolicyTest.class);
+        suite.addTestSuite(tests.security.permissions.JavaSecuritySecurityTest.class);
+        suite.addTestSuite(tests.security.permissions.JavaUtilLocale.class);
+        suite.addTestSuite(tests.security.permissions.JavaNetServerSocketTest.class);
+        suite.addTestSuite(tests.security.permissions.JavaNetDatagramSocketTest.class);
+        suite.addTestSuite(tests.security.permissions.JavaNetMulticastSocketTest.class);
+
+        return suite;
+    }
+    
+}
+
diff --git a/libcore/security/src/test/java/tests/security/permissions/JavaIoFileStreamTest.java b/libcore/security/src/test/java/tests/security/permissions/JavaIoFileStreamTest.java
new file mode 100644
index 0000000..20feee2
--- /dev/null
+++ b/libcore/security/src/test/java/tests/security/permissions/JavaIoFileStreamTest.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.security.permissions;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+/*
+ * This class tests the secrity permissions which are documented in
+ * http://java.sun.com/j2se/1.5.0/docs/guide/security/permissions.html#PermsAndMethods
+ * for class java.io.FileInputStream and java.io.FileOutputStream
+ */
+public class JavaIoFileStreamTest extends TestCase {
+    
+    SecurityManager old;
+
+    @Override
+    protected void setUp() throws Exception {
+        old = System.getSecurityManager();
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        System.setSecurityManager(old);
+        super.tearDown();
+    }
+   
+    public void test_FileInputStream() throws IOException {
+        class TestSecurityManager extends SecurityManager {
+            boolean called;
+            String file;
+            FileDescriptor fd;
+            void reset(){
+                called = false;
+                file = null;
+                fd = null;
+            }
+            @Override
+            public void checkRead(FileDescriptor fd) {
+                called = true;
+                this.fd = fd;
+                super.checkRead(fd);
+            }
+            @Override
+            public void checkRead(String file){
+                called = true;
+                this.file = file;
+                super.checkRead(file);
+            }
+        }
+
+        long id = new java.util.Date().getTime();
+        String filename = "SecurityPermissionsTest_"+id;
+        File f = File.createTempFile(filename, null);
+        f.deleteOnExit();
+        filename = f.getCanonicalPath();
+
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        FileDescriptor fd = new FileDescriptor();
+        new FileInputStream(fd);
+        assertTrue("FileDescriptor() ctor must call checkRead on security manager", s.called);
+        assertEquals("Argument of checkRead is not correct", fd, s.fd);
+        
+        s.reset();
+        new FileInputStream(filename);
+        assertTrue("FileDescriptor() ctor must call checkRead on security manager", s.called);
+        assertEquals("Argument of checkRead is not correct", filename, s.file);
+        
+        s.reset();
+        new FileInputStream(f);
+        assertTrue("FileDescriptor() ctor must call checkRead on security manager", s.called);
+        assertEquals("Argument of checkRead is not correct", filename, s.file);
+    }
+    
+    
+    public void test_FileOutputStream1() throws IOException {
+        class TestSecurityManager extends SecurityManager {
+            boolean called;
+            String file;
+            FileDescriptor fd;
+            void reset(){
+                called = false;
+                file = null;
+                fd = null;
+            }
+            @Override
+            public void checkWrite(FileDescriptor fd) {
+                called = true;
+                this.fd = fd;
+                super.checkWrite(fd);
+            }
+            @Override
+            public void checkWrite(String file){
+                called = true;
+                this.file = file;
+                super.checkWrite(file);
+            }
+        }
+
+        long id = new java.util.Date().getTime();
+        String filename = "SecurityPermissionsTest_"+id;
+        File f = File.createTempFile(filename, null);
+        f.deleteOnExit();
+        filename = f.getCanonicalPath();
+
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        FileDescriptor fd = new FileDescriptor();
+        new FileOutputStream(fd);
+        assertTrue("FileOutputStream(FileDescriptor) ctor must call checkWrite on security manager", s.called);
+        assertEquals("Argument of checkWrite is not correct", fd, s.fd);
+        
+        s.reset();
+        new FileOutputStream(f);
+        assertTrue("FileOutputStream(File) ctor must call checkWrite on security manager", s.called);
+        assertEquals("Argument of checkWrite is not correct", filename, s.file); 
+        
+        s.reset();
+        new FileOutputStream(filename);
+        assertTrue("FileOutputStream(String) ctor must call checkWrite on security manager", s.called);
+        assertEquals("Argument of checkWrite is not correct", filename, s.file);
+        
+        s.reset();
+        new FileOutputStream(filename, true);
+        assertTrue("FileOutputStream(String,boolean) ctor must call checkWrite on security manager", s.called);
+        assertEquals("Argument of checkWrite is not correct", filename, s.file); 
+    }
+    
+}
diff --git a/libcore/security/src/test/java/tests/security/permissions/JavaIoFileTest.java b/libcore/security/src/test/java/tests/security/permissions/JavaIoFileTest.java
new file mode 100644
index 0000000..d0e4982
--- /dev/null
+++ b/libcore/security/src/test/java/tests/security/permissions/JavaIoFileTest.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.security.permissions;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FilenameFilter;
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+/*
+ * This class tests the secrity permissions which are documented in
+ * http://java.sun.com/j2se/1.5.0/docs/guide/security/permissions.html#PermsAndMethods
+ * for class java.io.File.
+ */
+public class JavaIoFileTest extends TestCase {
+    
+    SecurityManager old;
+
+    @Override
+    protected void setUp() throws Exception {
+        old = System.getSecurityManager();
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        System.setSecurityManager(old);
+        super.tearDown();
+    }
+    
+
+    public void test_File1() throws IOException {
+        class TestSecurityManager extends SecurityManager {
+            boolean called;
+            String filename;
+            
+            void reset(){
+                called = false;
+                filename = null;
+            }
+            
+            @Override
+            public void checkDelete(String file) {
+                called = true;
+                this.filename = file;
+                super.checkDelete(file);
+            }
+        }
+        
+        long id = new java.util.Date().getTime();
+        String filename = "SecurityPermissionsTest_"+id;
+        File f = File.createTempFile(filename, null);
+        f.deleteOnExit();
+        filename = f.getCanonicalPath();
+
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        f.delete();
+        assertTrue("File.delete must call checkDelete on security manager", s.called);
+        assertEquals("Argument of checkDelete is not correct", filename, s.filename);
+        
+        s.reset();
+        f.deleteOnExit();
+        assertTrue("File.deleteOnExit must call checkDelete on security manager", s.called);        
+        assertEquals("Argument of checkDelete is not correct", filename, s.filename);
+    }
+    
+    
+    public void test_File2() throws IOException {
+        class TestSecurityManager extends SecurityManager {
+            boolean called;
+            String file;
+            void reset(){
+                called = false;
+                file = null;
+            }
+            @Override
+            public void checkRead(String file){
+                called = true;
+                this.file = file;
+                super.checkRead(file);
+            }
+        }
+
+        long id = new java.util.Date().getTime();
+        String filename = "SecurityPermissionsTest_"+id;
+        File f = File.createTempFile(filename, null);
+        f.deleteOnExit();
+        filename = f.getCanonicalPath();
+
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        f.exists();
+        assertTrue("File.exists() must call checkRead on security manager", s.called);
+        assertEquals("Argument of checkRead is not correct", filename, s.file);
+        
+        s.reset();
+        f.canRead();
+        assertTrue("File.canRead() must call checkRead on security manager", s.called);
+        assertEquals("Argument of checkRead is not correct", filename, s.file);
+        
+        s.reset();
+        f.isFile();
+        assertTrue("File.isFile() must call checkRead on security manager", s.called);
+        assertEquals("Argument of checkRead is not correct", filename, s.file);
+        
+        s.reset();
+        f.isDirectory();
+        assertTrue("File.isDirectory() must call checkRead on security manager", s.called);
+        assertEquals("Argument of checkRead is not correct", filename, s.file);
+        
+        s.reset();
+        f.isHidden();
+        assertTrue("File.isHidden() must call checkRead on security manager", s.called);
+        assertEquals("Argument of checkRead is not correct", filename, s.file);
+        
+        s.reset();
+        f.lastModified();
+        assertTrue("File.lastModified() must call checkRead on security manager", s.called);
+        assertEquals("Argument of checkRead is not correct", filename, s.file);
+        
+        s.reset();
+        f.length();
+        assertTrue("File.length() must call checkRead on security manager", s.called);
+        assertEquals("Argument of checkRead is not correct", filename, s.file);
+        
+        s.reset();
+        f.list();
+        assertTrue("File.list() must call checkRead on security manager", s.called);
+        assertEquals("Argument of checkRead is not correct", filename, s.file);
+        
+        s.reset();
+        f.list((FilenameFilter)null);
+        assertTrue("File.list(FilenameFilter) must call checkRead on security manager", s.called);
+        assertEquals("Argument of checkRead is not correct", filename, s.file);
+        
+        s.reset();
+        f.listFiles();
+        assertTrue("File.listFiles() must call checkRead on security manager", s.called);
+        assertEquals("Argument of checkRead is not correct", filename, s.file);
+        
+        s.reset();
+        f.listFiles((FilenameFilter)null);
+        assertTrue("File.listFiles(FilenameFilter) must call checkRead on security manager", s.called);
+        assertEquals("Argument of checkRead is not correct", filename, s.file);
+        
+        s.reset();
+        f.listFiles((FileFilter)null);
+        assertTrue("File.listFiles(FileFilter) must call checkRead on security manager", s.called);
+        assertEquals("Argument of checkRead is not correct", filename, s.file);
+    }
+
+
+    public void test_File3() throws IOException {
+        class TestSecurityManager extends SecurityManager {
+            boolean called;
+            String file;
+            void reset(){
+                called = false;
+                file = null;
+            }
+            @Override
+            public void checkWrite(String file){
+                called = true;
+                this.file = file;
+                super.checkWrite(file);
+            }
+        }
+
+        long id = new java.util.Date().getTime();
+        String filename  = "SecurityPermissionsTest_"+id;
+        String filename2 = "SecurityPermissionsTest_"+(id+1);
+        File f = File.createTempFile(filename, null);
+        f.deleteOnExit();
+        filename = f.getCanonicalPath();
+
+        File f2 = File.createTempFile(filename2, null);
+        f2.deleteOnExit();
+        filename2 = f2.getCanonicalPath();
+
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        f.canWrite();
+        assertTrue("File.canWrite() must call checkWrite on security manager", s.called);
+        assertEquals("Argument of checkWrite is not correct", filename, s.file);
+
+        s.reset();
+        f.createNewFile();
+        assertTrue("File.createNewFile() must call checkWrite on security manager", s.called);
+        assertEquals("Argument of checkWrite is not correct", filename, s.file);
+
+        s.reset();
+        File tmp = new File("/tmp/dir"+id);
+        tmp.mkdir();
+        assertTrue("File.canWrite() must call checkWrite on security manager", s.called);
+        assertEquals("Argument of checkWrite is not correct", "/tmp/dir"+id, s.file);
+
+        s.reset();
+        tmp = new File("/tmp/a"+id+"/b/c");
+        tmp.mkdirs();
+        assertTrue("File.mkdirs() must call checkWrite on security manager", s.called);
+        assertEquals("Argument of checkWrite is not correct", "/tmp/a"+id+"/b/c", s.file);
+        
+        s.reset();
+        f.renameTo(f2);
+        assertTrue("File.renameTo(File) must call checkWrite on security manager", s.called);
+        assertEquals("Argument of checkWrite is not correct", filename2, s.file);
+        
+        s.reset();
+        f.setLastModified(id);
+        assertTrue("File.setLastModified() must call checkWrite on security manager", s.called);
+        assertEquals("Argument of checkWrite is not correct", filename, s.file);
+        
+        s.reset();
+        f.setReadOnly();
+        assertTrue("File.setReadOnly() must call checkWrite on security manager", s.called);
+        assertEquals("Argument of checkWrite is not correct", filename, s.file);
+        
+        s.reset();
+        tmp = File.createTempFile("xxx", "yyy");
+        tmp.deleteOnExit();
+        filename = tmp.getCanonicalPath();
+        assertTrue("File.createTempFile(String,String) must call checkWrite on security manager", s.called);
+        assertEquals("Argument of checkWrite is not correct", filename, s.file);
+
+        s.reset();
+        tmp = File.createTempFile("xxx", "yyy", (File)null);
+        tmp.deleteOnExit();
+        filename = tmp.getCanonicalPath();
+        assertTrue("File.createTempFile(String,String,File) must call checkWrite on security manager", s.called);
+        assertEquals("Argument of checkWrite is not correct", filename, s.file);
+    }
+}
+
diff --git a/libcore/security/src/test/java/tests/security/permissions/JavaIoObjectStreamTest.java b/libcore/security/src/test/java/tests/security/permissions/JavaIoObjectStreamTest.java
new file mode 100644
index 0000000..f7b1333
--- /dev/null
+++ b/libcore/security/src/test/java/tests/security/permissions/JavaIoObjectStreamTest.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.security.permissions;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.NotActiveException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.SerializablePermission;
+import java.io.StreamCorruptedException;
+import java.security.Permission;
+
+import junit.framework.TestCase;
+
+/*
+ * This class tests the secrity permissions which are documented in
+ * http://java.sun.com/j2se/1.5.0/docs/guide/security/permissions.html#PermsAndMethods
+ * for classes
+ *    java.io.ObjectInputStream
+ *    java.io.ObjectOutputStream
+ */
+public class JavaIoObjectStreamTest extends TestCase {
+    
+    SecurityManager old;
+
+    @Override
+    protected void setUp() throws Exception {
+        old = System.getSecurityManager();
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        System.setSecurityManager(old);
+        super.tearDown();
+    }
+    
+  
+    public void test_ObjectInputStream() throws IOException {
+        class TestSecurityManager extends SecurityManager {
+            boolean called;
+            Permission permission;
+            void reset(){
+                called = false;
+                permission = null;
+            }
+            @Override
+            public void checkPermission(Permission permission){
+                if(permission instanceof SerializablePermission){
+                    called = true;
+                    this.permission = permission;
+                }
+                super.checkPermission(permission);
+            }
+        }
+        
+        // TestObjectInputStream is necessary in order to call enableResolveObject
+        class TestObjectInputStream extends ObjectInputStream  {
+            TestObjectInputStream(InputStream s) throws StreamCorruptedException, IOException {
+                super(s);
+            }
+            @Override
+            public boolean enableResolveObject(boolean enable) throws SecurityException {
+                return super.enableResolveObject(enable);
+            }
+        }
+
+        long id = new java.util.Date().getTime();
+        String filename  = "SecurityPermissionsTest_"+id;
+        File f = File.createTempFile(filename, null);
+        f.deleteOnExit();
+        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f));
+        oos.close();
+        TestObjectInputStream ois = new TestObjectInputStream(new FileInputStream(f));
+
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        ois.enableResolveObject(true);
+        assertTrue("ObjectInputStream.enableResolveObject(boolean) must call checkPermission on security manager", s.called);
+        assertEquals("Name of SerializablePermission is not correct", "enableSubstitution", s.permission.getName());
+    }
+
+    
+    public void test_ObjectOutputStream() throws IOException {
+        class TestSecurityManager extends SecurityManager {
+            boolean called;
+            Permission permission;
+            void reset(){
+                called = false;
+                permission = null;
+            }
+            @Override
+            public void checkPermission(Permission permission){
+                if(permission instanceof SerializablePermission){
+                    called = true;
+                    this.permission = permission;
+                }
+                super.checkPermission(permission);
+            }
+        }
+        
+        // TestObjectOutputStream is necessary in order to call enableReplaceObject
+        class TestObjectOutputStream extends ObjectOutputStream  {
+            TestObjectOutputStream(OutputStream s) throws StreamCorruptedException, IOException {
+                super(s);
+            }
+            @Override
+            public boolean enableReplaceObject(boolean enable) throws SecurityException {
+                return super.enableReplaceObject(enable);
+            }
+        }
+
+        long id = new java.util.Date().getTime();
+        String filename  = "SecurityPermissionsTest_"+id;
+        File f = File.createTempFile(filename, null);
+        f.deleteOnExit();
+
+        TestObjectOutputStream ois = new TestObjectOutputStream(new FileOutputStream(f));
+
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        ois.enableReplaceObject(true);
+        assertTrue("ObjectOutputStream.enableReplaceObject(boolean) must call checkPermission on security manager", s.called);
+        assertEquals("Name of SerializablePermission is not correct", "enableSubstitution", s.permission.getName());
+    }
+
+    
+    public void test_ObjectInputOutputStream() throws IOException {
+        class TestSecurityManager extends SecurityManager {
+            boolean called;
+            Permission permission;
+            void reset(){
+                called = false;
+                permission = null;
+            }
+            @Override
+            public void checkPermission(Permission permission){
+                if(permission instanceof SerializablePermission){
+                    called = true;
+                    this.permission = permission;
+                }
+                super.checkPermission(permission);
+            }
+        }
+        
+        // Beginning with J2SE 1.4.0, ObjectOutputStream's public one-argument constructor
+        // requires the "enableSubclassImplementation" SerializablePermission when invoked
+        // (either directly or indirectly) by a subclass which overrides 
+        // ObjectOutputStream.putFields or ObjectOutputStream.writeUnshared.
+        //
+        // Also beginning with J2SE 1.4.0, ObjectInputStream's public one-argument 
+        // constructor requires the "enableSubclassImplementation" SerializablePermission 
+        // when invoked (either directly or indirectly) by a subclass which overrides 
+        // ObjectInputStream.readFields or ObjectInputStream.readUnshared.
+
+        class TestObjectOutputStream extends ObjectOutputStream  {
+            TestObjectOutputStream(OutputStream s) throws StreamCorruptedException, IOException {
+                super(s);
+            }
+        }
+        
+        class TestObjectOutputStream_putFields extends ObjectOutputStream  {
+            TestObjectOutputStream_putFields(OutputStream s) throws StreamCorruptedException, IOException {
+                super(s);
+            }
+            @Override 
+            public PutField putFields() throws IOException {
+                return super.putFields();
+            }
+        }
+        
+        class TestObjectOutputStream_writeUnshared extends ObjectOutputStream  {
+            TestObjectOutputStream_writeUnshared(OutputStream s) throws StreamCorruptedException, IOException {
+                super(s);
+            }
+            @Override 
+            public void writeUnshared(Object object) throws IOException {
+                super.writeUnshared(object);
+            }
+
+        }
+        
+        class TestObjectInputStream extends ObjectInputStream  {
+            TestObjectInputStream(InputStream s) throws StreamCorruptedException, IOException {
+                super(s);
+            }
+        }
+        
+        class TestObjectInputStream_readFields extends ObjectInputStream  {
+            TestObjectInputStream_readFields(InputStream s) throws StreamCorruptedException, IOException {
+                super(s);
+            }
+            @Override
+            public GetField readFields() throws IOException, ClassNotFoundException, NotActiveException {
+                return super.readFields();
+            }
+        }
+        
+        class TestObjectInputStream_readUnshared extends ObjectInputStream  {
+            TestObjectInputStream_readUnshared(InputStream s) throws StreamCorruptedException, IOException {
+                super(s);
+            }
+            @Override
+            public Object readUnshared() throws IOException, ClassNotFoundException {
+                return super.readUnshared();
+            }
+        }
+        
+        
+        long id = new java.util.Date().getTime();
+        String filename  = "SecurityPermissionsTest_"+id;
+        File f = File.createTempFile(filename, null);
+        f.deleteOnExit();
+        
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        new ObjectOutputStream(new FileOutputStream(f));
+        assertTrue("ObjectOutputStream(OutputStream) ctor must not call checkPermission on security manager on a class which neither overwrites writeUnshared nor putFields", !s.called);
+        
+        s.reset();
+        new TestObjectOutputStream(new FileOutputStream(f));
+        assertTrue("ObjectOutputStream(OutputStream) ctor must not call checkPermission on security manager on a class which neither overwrites writeUnshared nor putFields", !s.called);
+        
+        s.reset();
+        new TestObjectOutputStream_writeUnshared(new FileOutputStream(f));
+        assertTrue("ObjectOutputStream(OutputStream) ctor must call checkPermission on security manager on a class which overwrites method writeUnshared", s.called);
+        assertEquals("Name of SerializablePermission is not correct", "enableSubclassImplementation", s.permission.getName());
+        
+        s.reset();
+        new TestObjectOutputStream_putFields(new FileOutputStream(f));
+        assertTrue("ObjectOutputStream(OutputStream) ctor must call checkPermission on security manager on a class which overwrites method putFields", s.called);
+        assertEquals("Name of SerializablePermission is not correct", "enableSubclassImplementation", s.permission.getName());
+        
+        
+        s.reset();
+        new ObjectInputStream(new FileInputStream(f));
+        assertTrue("ObjectOutputStream(OutputStream) ctor must not call checkPermission on security manager on a class which neither overwrites methods readFields nor readUnshared", !s.called);
+        
+        s.reset();
+        new TestObjectInputStream(new FileInputStream(f));
+        assertTrue("ObjectOutputStream(OutputStream) ctor must not call checkPermission on security manager on a class which neither overwrites methods readFields nor readUnshared", !s.called);
+        
+        s.reset();
+        new TestObjectInputStream_readFields(new FileInputStream(f));
+        assertTrue("ObjectOutputStream(OutputStream) ctor must call checkPermission on security manager on a class which overwrites method readFields", s.called);
+        assertEquals("Name of SerializablePermission is not correct", "enableSubclassImplementation", s.permission.getName());
+        
+        s.reset();
+        new TestObjectInputStream_readUnshared(new FileInputStream(f));
+        assertTrue("ObjectOutputStream(OutputStream) ctor must call checkPermission on security manager on a class which overwrites method readUnshared", s.called);
+        assertEquals("Name of SerializablePermission is not correct", "enableSubclassImplementation", s.permission.getName());
+    }
+    
+}
diff --git a/libcore/security/src/test/java/tests/security/permissions/JavaIoRandomAccessFileTest.java b/libcore/security/src/test/java/tests/security/permissions/JavaIoRandomAccessFileTest.java
new file mode 100644
index 0000000..eab6cb2
--- /dev/null
+++ b/libcore/security/src/test/java/tests/security/permissions/JavaIoRandomAccessFileTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.security.permissions;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+import junit.framework.TestCase;
+
+/*
+ * This class tests the secrity permissions which are documented in
+ * http://java.sun.com/j2se/1.5.0/docs/guide/security/permissions.html#PermsAndMethods
+ * for class java.io.RandomAccessFile
+ */
+public class JavaIoRandomAccessFileTest extends TestCase {
+    
+    SecurityManager old;
+
+    @Override
+    protected void setUp() throws Exception {
+        old = System.getSecurityManager();
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        System.setSecurityManager(old);
+        super.tearDown();
+    }
+    
+    public void test_RandomAccessFile1() throws IOException {
+        class TestSecurityManager extends SecurityManager {
+            boolean called;
+            String file;
+            void reset(){
+                called = false;
+                file = null;
+            }
+            @Override
+            public void checkRead(String file){
+                called = true;
+                this.file = file;
+                super.checkRead(file);
+            }
+        }
+
+        long id = new java.util.Date().getTime();
+        String filename = "SecurityPermissionsTest_"+id;
+        File f = File.createTempFile(filename, null);
+        f.deleteOnExit();
+        filename = f.getCanonicalPath();
+        
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        new RandomAccessFile(filename, "r");
+        assertTrue("RandomAccessFile(String,String) ctor must call checkRead on security manager", s.called);
+        assertEquals("Argument of checkRead is not correct", filename, s.file);
+        
+        s.reset();
+        new RandomAccessFile(f, "r");
+        assertTrue("RandomAccessFile(File, String) ctor must call checkRead on security manager", s.called);
+        assertEquals("Argument of checkRead is not correct", filename, s.file);
+    }
+    
+    
+    public void test_RandomAccessFile2() throws IOException {
+        class TestSecurityManager extends SecurityManager {
+            boolean checkReadCalled;
+            boolean checkWriteCalled;
+            String checkReadFile;
+            String checkWriteFile;
+            
+            void reset(){
+                checkReadCalled = false;
+                checkWriteCalled = false;
+                checkReadFile = null;
+                checkWriteFile = null;
+            }
+            
+            @Override
+            public void checkRead(String file) {
+                checkReadCalled = true;
+                this.checkReadFile = file;
+                super.checkRead(file);
+            }
+            @Override
+            public void checkWrite(String file) {
+                checkWriteCalled = true;
+                this.checkWriteFile = file;
+                super.checkWrite(file);
+            }
+        }
+
+        long id = new java.util.Date().getTime();
+        String filename = "SecurityPermissionsTest_"+id;
+        File f = File.createTempFile(filename, null);
+        f.deleteOnExit();
+        filename = f.getCanonicalPath();
+        
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        new RandomAccessFile(filename, "rw");
+        assertTrue("RandomAccessFile(String,String) ctor must call checkRead on security manager", s.checkReadCalled);
+        assertTrue("RandomAccessFile(String,String) ctor must call checkWrite on security manager", s.checkWriteCalled);
+        assertEquals("Argument of checkRead is not correct", filename, s.checkReadFile);
+        assertEquals("Argument of checkWrite is not correct", filename, s.checkWriteFile);
+    }
+}
diff --git a/libcore/security/src/test/java/tests/security/permissions/JavaLangClassLoaderTest.java b/libcore/security/src/test/java/tests/security/permissions/JavaLangClassLoaderTest.java
new file mode 100644
index 0000000..42747a6
--- /dev/null
+++ b/libcore/security/src/test/java/tests/security/permissions/JavaLangClassLoaderTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.security.permissions;
+
+import java.security.Permission;
+
+import junit.framework.TestCase;
+
+/*
+ * This class tests the secrity permissions which are documented in
+ * http://java.sun.com/j2se/1.5.0/docs/guide/security/permissions.html#PermsAndMethods
+ * for class java.lang.ClassLoader
+ */
+public class JavaLangClassLoaderTest extends TestCase {
+    
+    SecurityManager old;
+
+    @Override
+    protected void setUp() throws Exception {
+        old = System.getSecurityManager();
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        System.setSecurityManager(old);
+        super.tearDown();
+    }
+    
+    
+    public void test_ClassLoaderCtor () {
+        class TestSecurityManager extends SecurityManager {
+            boolean called;
+            void reset(){
+                called = false;
+            }
+            @Override
+            public void checkCreateClassLoader(){
+                called = true;
+                super.checkCreateClassLoader();
+            }
+        }
+        
+        class MyClassLoader extends ClassLoader { 
+            MyClassLoader(){super();}
+            MyClassLoader(ClassLoader parent){super(parent);}            
+        }
+
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        ClassLoader c1 = new MyClassLoader();
+        assertTrue("ClassLoader ctor must call checkCreateClassLoader on security manager", s.called);
+
+        s.reset();
+        ClassLoader c2 = new MyClassLoader(c1);
+        assertTrue("ClassLoader ctor must call checkCreateClassLoader on security manager", s.called);
+    }
+    
+    public void test_getSystemClassLoader () {
+        class TestSecurityManager extends SecurityManager {
+            boolean called;
+            void reset(){
+                called = false;
+            }
+            @Override
+            public void checkPermission(Permission permission){
+                if(permission instanceof RuntimePermission && "getClassLoader".equals(permission.getName())){
+                    called = true;
+                }
+                super.checkPermission(permission);
+            }
+        }
+        
+        //System.out.println(ClassLoaderTest.class.getClassLoader());
+        //=>PathClassLoader
+
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        // TODO
+        // a new Class has to be defined in a new ClassLoader, then
+        // the check will be performed.
+        
+        s.reset();
+        ClassLoader.getSystemClassLoader();
+        assertTrue("ClassLoader.getSystemClassLoader() must check RuntimePermission(getClassLoader) on security manager", s.called);
+    }
+}
+
diff --git a/libcore/security/src/test/java/tests/security/permissions/JavaLangClassTest.java b/libcore/security/src/test/java/tests/security/permissions/JavaLangClassTest.java
new file mode 100644
index 0000000..fada38f
--- /dev/null
+++ b/libcore/security/src/test/java/tests/security/permissions/JavaLangClassTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.security.permissions;
+
+import java.security.Permission;
+
+import junit.framework.TestCase;
+
+/*
+ * This class tests the secrity permissions which are documented in
+ * http://java.sun.com/j2se/1.5.0/docs/guide/security/permissions.html#PermsAndMethods
+ * for class java.lang.Class
+ */
+public class JavaLangClassTest extends TestCase {
+    
+    SecurityManager old;
+
+    @Override
+    protected void setUp() throws Exception {
+        old = System.getSecurityManager();
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        System.setSecurityManager(old);
+        super.tearDown();
+    }
+    
+    
+    public void test_getProtectionDomain () {
+        class TestSecurityManager extends SecurityManager {
+            boolean called;
+            void reset(){
+                called = false;
+            }
+            @Override
+            public void checkPermission(Permission permission){
+                if(permission instanceof RuntimePermission && "getProtectionDomain".equals(permission.getName())){
+                    called = true;
+                }
+                super.checkPermission(permission);
+            }
+        }
+
+        Class c = java.lang.String.class;
+        assertTrue("java.lang.String.class not assigned", c != null);
+
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        c.getProtectionDomain();
+        assertTrue("Class.getProtectionDomain() must check RuntimePermission(\"getProtectionDomain\") on security manager", s.called);
+    }
+
+    public void test_Class() throws ClassNotFoundException {
+        class TestSecurityManager extends SecurityManager {
+            boolean called;
+            void reset(){
+                called = false;
+            }
+            @Override
+            public void checkPermission(Permission permission){
+                if(permission instanceof RuntimePermission && "getClassLoader".equals(permission.getName())){
+                    called = true;
+                }
+                super.checkPermission(permission);
+            }
+        }
+
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        Class.forName("java.lang.String", true, null);
+        assertTrue("Class.forName(String,boolean,Classloader) must check RuntimePermission(getClassLoader) on security manager", s.called);
+    }
+    
+}
diff --git a/libcore/security/src/test/java/tests/security/permissions/JavaLangSystemTest.java b/libcore/security/src/test/java/tests/security/permissions/JavaLangSystemTest.java
new file mode 100644
index 0000000..8ac3a30
--- /dev/null
+++ b/libcore/security/src/test/java/tests/security/permissions/JavaLangSystemTest.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.security.permissions;
+
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.security.Permission;
+import java.util.Properties;
+import java.util.PropertyPermission;
+
+import junit.framework.TestCase;
+
+/*
+ * This class tests the secrity permissions which are documented in
+ * http://java.sun.com/j2se/1.5.0/docs/guide/security/permissions.html#PermsAndMethods
+ * for class java.lang.System
+ */
+public class JavaLangSystemTest extends TestCase {
+    
+    SecurityManager old;
+
+    @Override
+    protected void setUp() throws Exception {
+        old = System.getSecurityManager();
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        System.setSecurityManager(old);
+        super.tearDown();
+    }
+    
+    public void test_Properties() {
+        class TestSecurityManager extends SecurityManager {
+            boolean called;
+            
+            void reset(){
+                called = false;
+            }
+            
+            @Override
+            public void checkPropertiesAccess() {
+                called = true;
+                super.checkPropertiesAccess();
+            }
+        }
+        
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        Properties props = System.getProperties();
+        assertTrue("System.getProperties must call checkPropertiesAccess on security manager", s.called);
+        
+        s.reset();
+        System.setProperties(props);
+        assertTrue("System.setProperties must call checkPropertiesAccess on security manager", s.called);
+    }
+    
+    public void test_getProperty() {
+        class TestSecurityManager extends SecurityManager {
+            boolean called;
+            String key;
+            
+            void reset(){
+                called = false;
+                key = null;
+            }
+            
+            @Override
+            public void checkPropertyAccess(String key) {
+                called = true;
+                this.key = key;
+                super.checkPropertyAccess(key);
+            }
+        }
+        
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        System.getProperty("key");
+        assertTrue("System.getProperty must call checkPropertyAccess on security manager", s.called);
+        assertEquals("Argument of checkPropertyAccess is not correct", "key", s.key);
+        
+        s.reset();
+        System.getProperty("key", "value");
+        assertTrue("System.getProperty must call checkPropertyAccess on security manager", s.called);
+        assertEquals("Argument of checkPropertyAccess is not correct", "key", s.key);
+    }
+
+    public void test_setProperty() {
+        class TestSecurityManager extends SecurityManager {
+            boolean called;
+            Permission p;
+            
+            void reset(){
+                called = false;
+                p = null;
+            }
+            
+            @Override
+            public void checkPermission(Permission p) {
+                called = true;
+                this.p = p;
+                super.checkPermission(p);
+            }
+        }
+        
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        System.setProperty("key", "value");
+        assertTrue("System.setProperty must call checkPermission on security manager", s.called);
+        assertEquals("Argument of checkPermission is not correct", new PropertyPermission("key", "write"), s.p);
+    }
+
+    public void test_setSecurityManager() {
+        class TestSecurityManager extends SecurityManager {
+            boolean called = false;
+            @Override
+            public void checkPermission(Permission permission) {
+                if(permission instanceof RuntimePermission && "setSecurityManager".equals(permission.getName())){
+                    called = true;              
+                }
+                super.checkPermission(permission);
+            }
+            
+        }
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        System.setSecurityManager(s);
+        assertTrue("System.setSecurityManager must check security permissions", s.called);
+    }
+    
+    public void test_setInOutErr() {
+        class TestSecurityManager extends SecurityManager {
+            boolean called;
+            Permission p;
+            
+            void reset(){
+                called = false;
+                p = null;
+            }
+            
+            @Override
+            public void checkPermission(Permission p) {
+                called = true;
+                this.p = p;
+                super.checkPermission(p);
+            }
+        }
+        
+        InputStream in = System.in;
+        PrintStream out = System.out;
+        PrintStream err = System.err;
+        Permission p = new RuntimePermission("setIO");
+
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        System.setIn(in);
+        assertTrue("System.setIn(Inputstream) must call checkPermission on security manager", s.called);
+        assertEquals("Argument of checkPermission is not correct", p, s.p);
+
+        System.setOut(err);
+        assertTrue("System.setOut(PrintStream) must call checkPermission on security manager", s.called);
+        assertEquals("Argument of checkPermission is not correct", p, s.p);
+
+        System.setErr(out);
+        assertTrue("System.setErr(PrintStream) must call checkPermission on security manager", s.called);
+        assertEquals("Argument of checkPermission is not correct", p, s.p);
+    }
+}
+
diff --git a/libcore/security/src/test/java/tests/security/permissions/JavaNetDatagramSocketTest.java b/libcore/security/src/test/java/tests/security/permissions/JavaNetDatagramSocketTest.java
new file mode 100644
index 0000000..b7e4a6c
--- /dev/null
+++ b/libcore/security/src/test/java/tests/security/permissions/JavaNetDatagramSocketTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.security.permissions;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+
+import junit.framework.TestCase;
+
+/*
+ * This class tests the secrity permissions which are documented in
+ * http://java.sun.com/j2se/1.5.0/docs/guide/security/permissions.html#PermsAndMethods
+ * for class java.net.DatagramSocket
+ */
+public class JavaNetDatagramSocketTest extends TestCase {
+    
+    SecurityManager old;
+
+    @Override
+    protected void setUp() throws Exception {
+        old = System.getSecurityManager();
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        System.setSecurityManager(old);
+        super.tearDown();
+    }
+    
+    public void test_ctor() throws IOException {
+        class TestSecurityManager extends SecurityManager {
+            boolean called = false;
+            String host = null;
+            int port = 0;
+            void reset(){
+                called = false;
+                host = null;
+                port = 0;
+            }
+            @Override
+            public void checkListen(int port) {
+                called = true;
+                this.port = port;
+                super.checkListen(port);
+            }
+            @Override
+            public void checkAccept(String host, int port) {
+                this.host = host;
+                this.port = port;
+                super.checkAccept(host, port);
+            }
+        }
+        
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        DatagramSocket s1 = new DatagramSocket(8881);
+        assertTrue("java.net.DatagramSocket ctor must call checkListen on security manager", s.called);
+        assertEquals("Argument of checkListen is not correct", 8881, s.port);
+        
+        s.reset();
+        DatagramSocket s2 = new DatagramSocket();
+        assertTrue("java.net.DatagramSocket ctor must call checkListen on security manager", s.called);
+        assertEquals("Argument of checkListen is not correct", 0, s.port);
+        
+        s.reset();
+        DatagramSocket s3 = new DatagramSocket(new InetSocketAddress(8882));
+        assertTrue("java.net.DatagramSocket ctor must call checkListen on security manager", s.called);
+        assertEquals("Argument of checkListen is not correct", 8882, s.port);
+        
+        s.reset();
+        DatagramSocket s4 = new DatagramSocket(8883, InetAddress.getLocalHost());
+        assertTrue("java.net.DatagramSocket ctor must call checkListen on security manager", s.called);
+        assertEquals("Argument of checkListen is not correct", 8883, s.port);
+        
+        
+        DatagramPacket p = new DatagramPacket(new byte[256], 0, 256);
+        
+        s1.setSoTimeout(0);
+        s.reset();
+        assert(s1.getInetAddress()==null);
+        s1.receive(p);
+        assertTrue("java.net.DatagramSocket.receive must call checkAccept on security manager", s.called);
+    }
+    
+}
+
diff --git a/libcore/security/src/test/java/tests/security/permissions/JavaNetMulticastSocketTest.java b/libcore/security/src/test/java/tests/security/permissions/JavaNetMulticastSocketTest.java
new file mode 100644
index 0000000..cab7b04
--- /dev/null
+++ b/libcore/security/src/test/java/tests/security/permissions/JavaNetMulticastSocketTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.security.permissions;
+
+import java.io.IOException;
+import java.net.MulticastSocket;
+
+import junit.framework.TestCase;
+
+/*
+ * This class tests the secrity permissions which are documented in
+ * http://java.sun.com/j2se/1.5.0/docs/guide/security/permissions.html#PermsAndMethods
+ * for class java.net.MulticastSocket
+ */
+public class JavaNetMulticastSocketTest extends TestCase {
+    
+    SecurityManager old;
+
+    @Override
+    protected void setUp() throws Exception {
+        old = System.getSecurityManager();
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        System.setSecurityManager(old);
+        super.tearDown();
+    }
+    
+    public void test_ctor() throws IOException {
+        class TestSecurityManager extends SecurityManager {
+            boolean called = false;
+            int port = 0;
+            void reset(){
+                called = false;
+                port = 0;
+            }
+            @Override
+            public void checkListen(int port) {
+                called = true;
+                this.port = port;
+                super.checkListen(port);
+            }
+        }
+        
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        new MulticastSocket(8888);
+        assertTrue("java.net.MulticastSocket(int) ctor must call checkListen on security permissions", s.called);
+        assertEquals("Argument of checkListen is not correct", 8888, s.port);
+        
+        s.reset();
+        new MulticastSocket(0);
+        assertTrue("java.net.MulticastSocket() ctor must call checkListen on security permissions", s.called);
+        assertEquals("Argument of checkListen is not correct", 0, s.port);
+    }    
+}
diff --git a/libcore/security/src/test/java/tests/security/permissions/JavaNetServerSocketTest.java b/libcore/security/src/test/java/tests/security/permissions/JavaNetServerSocketTest.java
new file mode 100644
index 0000000..2e43038
--- /dev/null
+++ b/libcore/security/src/test/java/tests/security/permissions/JavaNetServerSocketTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.security.permissions;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+
+import junit.framework.TestCase;
+
+/*
+ * This class tests the secrity permissions which are documented in
+ * http://java.sun.com/j2se/1.5.0/docs/guide/security/permissions.html#PermsAndMethods
+ * for class java.net.ServerSocket
+ */
+public class JavaNetServerSocketTest extends TestCase {
+    
+    SecurityManager old;
+
+    @Override
+    protected void setUp() throws Exception {
+        old = System.getSecurityManager();
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        System.setSecurityManager(old);
+        super.tearDown();
+    }
+    
+    public void test_ctor() throws IOException {
+        class TestSecurityManager extends SecurityManager {
+            boolean called = false;
+            int port = 0;
+            void reset(){
+                called = false;
+                port = 0;
+            }
+            @Override
+            public void checkListen(int port) {
+                called = true;
+                this.port = port;
+                super.checkListen(port);
+            }
+        }
+        
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        ServerSocket ss  = new ServerSocket(8888);
+        assertTrue("java.net.ServerSocket ctor must call checkListen on security permissions", s.called);
+        assertEquals("Argument of checkListen is not correct", 8888, s.port);
+        
+        ss.close();
+    }
+}
diff --git a/libcore/security/src/test/java/tests/security/permissions/JavaNetSocketTest.java b/libcore/security/src/test/java/tests/security/permissions/JavaNetSocketTest.java
new file mode 100644
index 0000000..97a7519
--- /dev/null
+++ b/libcore/security/src/test/java/tests/security/permissions/JavaNetSocketTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.security.permissions;
+
+import java.io.IOException;
+import java.net.Socket;
+
+import junit.framework.TestCase;
+
+/*
+ * This class tests the secrity permissions which are documented in
+ * http://java.sun.com/j2se/1.5.0/docs/guide/security/permissions.html#PermsAndMethods
+ * for class java.net.Socket
+ */
+public class JavaNetSocketTest extends TestCase {
+    
+    SecurityManager old;
+
+    @Override
+    protected void setUp() throws Exception {
+        old = System.getSecurityManager();
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        System.setSecurityManager(old);
+        super.tearDown();
+    }
+    
+    public void test_ctor() throws IOException {
+        class TestSecurityManager extends SecurityManager {
+            boolean called = false;
+            String host = null;
+            int port = 0;
+            void reset(){
+                called = false;
+                host = null;
+                port = 0;
+            }
+            @Override
+            public void checkConnect(String host, int port) {
+                this.called = true;
+                this.port = port;
+                this.host = host;
+                super.checkConnect(host, port);
+            }
+        }
+        
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        String host = "www.google.ch";
+        int port = 80;
+        new Socket(host, port);
+        assertTrue("java.net.ServerSocket ctor must call checkConnect on security permissions", s.called);
+        assertEquals("Argument of checkConnect is not correct", host, s.host);
+        assertEquals("Argument of checkConnect is not correct", port, s.port);
+    }
+    
+}
diff --git a/libcore/security/src/test/java/tests/security/permissions/JavaSecurityPolicyTest.java b/libcore/security/src/test/java/tests/security/permissions/JavaSecurityPolicyTest.java
new file mode 100644
index 0000000..f3e9bbd
--- /dev/null
+++ b/libcore/security/src/test/java/tests/security/permissions/JavaSecurityPolicyTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.security.permissions;
+
+import java.security.Permission;
+import java.security.Policy;
+import java.security.SecurityPermission;
+
+import junit.framework.TestCase;
+
+/*
+ * This class tests the secrity permissions which are documented in
+ * http://java.sun.com/j2se/1.5.0/docs/guide/security/permissions.html#PermsAndMethods
+ * for class java.security.Policy
+ */
+public class JavaSecurityPolicyTest extends TestCase {
+    
+    SecurityManager old;
+
+    @Override
+    protected void setUp() throws Exception {
+        old = System.getSecurityManager();
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        System.setSecurityManager(old);
+        super.tearDown();
+    }
+    
+    public void test_getPolicy() {
+        class TestSecurityManager extends SecurityManager {
+            boolean called = false;
+            void reset(){
+                called = false;
+            }
+            @Override
+            public void checkPermission(Permission permission) {
+                if(permission instanceof SecurityPermission && "getPolicy".equals(permission.getName())){
+                    called = true;              
+                }
+                super.checkPermission(permission);
+            }
+            
+        }
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        Policy.getPolicy();
+        assertTrue("java.security.Policy.getPolicy() must call checkPermission on security permissions", s.called);
+    }
+    
+    public void test_setPolicy() {
+        class TestSecurityManager extends SecurityManager {
+            boolean called = false;
+            void reset(){
+                called = false;
+            }
+            @Override
+            public void checkPermission(Permission permission) {
+                if(permission instanceof SecurityPermission && "setPolicy".equals(permission.getName())){
+                    called = true;              
+                }
+                super.checkPermission(permission);
+            }
+            
+        }
+        
+        Policy p = Policy.getPolicy();
+        
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        Policy.setPolicy(p);
+        assertTrue("java.security.Policy.setPolicy() must call checkPermission on security permissions", s.called);
+    }
+}
diff --git a/libcore/security/src/test/java/tests/security/permissions/JavaSecuritySecurityTest.java b/libcore/security/src/test/java/tests/security/permissions/JavaSecuritySecurityTest.java
new file mode 100644
index 0000000..30a7774
--- /dev/null
+++ b/libcore/security/src/test/java/tests/security/permissions/JavaSecuritySecurityTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.security.permissions;
+
+import java.security.Permission;
+import java.security.Provider;
+import java.security.Security;
+import java.security.SecurityPermission;
+import java.util.HashSet;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+/*
+ * This class tests the secrity permissions which are documented in
+ * http://java.sun.com/j2se/1.5.0/docs/guide/security/permissions.html#PermsAndMethods
+ * for class java.security.Security
+ */
+public class JavaSecuritySecurityTest extends TestCase {
+    
+    SecurityManager old;
+
+    @Override
+    protected void setUp() throws Exception {
+        old = System.getSecurityManager();
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        System.setSecurityManager(old);
+        super.tearDown();
+    }
+    
+    public void test_getProperty() {
+        class TestSecurityManager extends SecurityManager {
+            boolean called = false;
+            void reset(){
+                called = false;
+            }
+            @Override
+            public void checkPermission(Permission permission) {
+                if(permission instanceof SecurityPermission && "getProperty.key".equals(permission.getName())){
+                    called = true;              
+                }
+                super.checkPermission(permission);
+            }
+            
+        }
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        Security.getProperty("key");
+        assertTrue("java.security.Security.getProperty() must call checkPermission on security permissions", s.called);
+    }
+    
+    public void test_setProperty() {
+        class TestSecurityManager extends SecurityManager {
+            boolean called = false;
+            String target = null;
+            void reset(){
+                called = false;
+                target = null;
+            }
+            @Override
+            public void checkSecurityAccess(String target) {
+                called = true;       
+                this.target = target;
+                super.checkSecurityAccess(target);
+            }
+            
+        }
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        Security.setProperty("key", "value");
+        assertTrue("java.security.Security.setProperty() must call checkSecurityAccess on security manager", s.called);
+        assertEquals("Argument of checkSecurityAccess is not correct", "setProperty.key", s.target);
+    }
+    
+    public void test_Provider() {
+        class TestSecurityManager extends SecurityManager {
+            boolean called = false;
+            Set<String> targets = new HashSet<String>();
+            void reset(){
+                called = false;
+                targets.clear();
+            }
+            @Override
+            public void checkSecurityAccess(String target) {
+                called = true;       
+                this.targets.add(target);
+                super.checkSecurityAccess(target);
+            }
+            
+        }
+        
+        class MyProvider extends Provider {
+            private static final long serialVersionUID = 1L;
+            MyProvider(){
+                super("DummyProvider", 1.0, "Provider for test purposes only");
+            }
+        }
+        
+        Provider p = new MyProvider();
+        
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();        
+        Security.addProvider(p);
+        assertTrue("java.security.Security.addProvider() must call checkSecurityAccess on security manager", s.called);
+        assertTrue("Argument of checkSecurityAccess is not correct", s.targets.contains("insertProvider.DummyProvider"));
+        
+        s.reset();        
+        Security.removeProvider(p.getName());
+        assertTrue("java.security.Security.removeProvider() must call checkSecurityAccess on security manager", s.called);
+        assertTrue("Argument of checkSecurityAccess is not correct", s.targets.contains("removeProvider.DummyProvider"));
+    }
+}
diff --git a/libcore/security/src/test/java/tests/security/permissions/JavaUtilLocale.java b/libcore/security/src/test/java/tests/security/permissions/JavaUtilLocale.java
new file mode 100644
index 0000000..e0562b1
--- /dev/null
+++ b/libcore/security/src/test/java/tests/security/permissions/JavaUtilLocale.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.security.permissions;
+
+import java.security.Permission;
+import java.util.Locale;
+import java.util.PropertyPermission;
+
+import junit.framework.TestCase;
+
+/*
+ * This class tests the secrity permissions which are documented in
+ * http://java.sun.com/j2se/1.5.0/docs/guide/security/permissions.html#PermsAndMethods
+ * for class java.util.Locale
+ */
+public class JavaUtilLocale extends TestCase {
+    
+    SecurityManager old;
+
+    @Override
+    protected void setUp() throws Exception {
+        old = System.getSecurityManager();
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        System.setSecurityManager(old);
+        super.tearDown();
+    }
+    
+    public void test_setDefault() {
+        class TestSecurityManager extends SecurityManager {
+            boolean called = false;
+            void reset(){
+                called = false;
+            }
+            @Override
+            public void checkPermission(Permission permission) {
+                if(permission instanceof PropertyPermission 
+                        && "user.language".equals(permission.getName())
+                        && "write".equals(permission.getActions())){
+                    called = true;              
+                }
+                super.checkPermission(permission);
+            }
+            
+        }
+        
+        Locale loc = Locale.getDefault();
+        
+        TestSecurityManager s = new TestSecurityManager();
+        System.setSecurityManager(s);
+        
+        s.reset();
+        Locale.setDefault(loc);
+        assertTrue("java.util.Locale.setDefault(Locale) must call checkPermission on security permissions", s.called);
+    }
+}